py 2.3 compat for lightwave_import and wizard_curve2tree
[blender.git] / release / scripts / wizard_curve2tree.py
1 #!BPY
2 """
3 Name: 'Tree from Curves'
4 Blender: 245
5 Group: 'Wizards'
6 Tip: 'Generate trees from curve shapes'
7 """
8
9 __author__ = "Campbell Barton"
10 __url__ = ['www.blender.org', 'blenderartists.org']
11 __version__ = "0.1"
12
13 __bpydoc__ = """\
14
15 """
16
17 # --------------------------------------------------------------------------
18 # Tree from Curves v0.1 by Campbell Barton (AKA Ideasman42)
19 # --------------------------------------------------------------------------
20 # ***** BEGIN GPL LICENSE BLOCK *****
21 #
22 # This program is free software; you can redistribute it and/or
23 # modify it under the terms of the GNU General Public License
24 # as published by the Free Software Foundation; either version 2
25 # of the License, or (at your option) any later version.
26 #
27 # This program is distributed in the hope that it will be useful,
28 # but WITHOUT ANY WARRANTY; without even the implied warranty of
29 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
30 # GNU General Public License for more details.
31 #
32 # You should have received a copy of the GNU General Public License
33 # along with this program; if not, write to the Free Software Foundation,
34 # Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
35 #
36 # ***** END GPL LICENCE BLOCK *****
37 # --------------------------------------------------------------------------
38
39 import bpy
40 import Blender
41 import BPyMesh
42 from Blender.Mathutils import Vector, Matrix, CrossVecs, AngleBetweenVecs, LineIntersect, TranslationMatrix, ScaleMatrix, RotationMatrix, Rand
43 from Blender.Geometry import ClosestPointOnLine
44 from Blender.Noise import randuvec
45
46 GLOBALS = {}
47 GLOBALS['non_bez_error'] = 0
48
49 '''
50 def debugVec(v1,v2):
51         sce = bpy.data.scenes.active
52         me = bpy.data.meshes.new()
53         me.verts.extend( [v1,v2] )
54         me.edges.extend( [(0,1)] )
55         sce.objects.new(me)
56 '''
57
58 def AngleBetweenVecsSafe(a1, a2):
59         try:
60                 return AngleBetweenVecs(a1,a2)
61         except:
62                 return 180.0
63
64 # Copied from blender, we could wrap this! - BKE_curve.c
65 # But probably not toooo bad in python
66 def forward_diff_bezier(q0, q1, q2, q3, pointlist, steps, axis):
67         f= float(steps)
68         rt0= q0
69         rt1= 3.0*(q1-q0)/f
70         f*= f
71         rt2= 3.0*(q0-2.0*q1+q2)/f
72         f*= steps
73         rt3= (q3-q0+3.0*(q1-q2))/f
74         
75         q0= rt0
76         q1= rt1+rt2+rt3
77         q2= 2*rt2+6*rt3
78         q3= 6*rt3
79         if axis == None:
80                 for a in xrange(steps+1):
81                         pointlist[a] = q0
82                         q0+= q1
83                         q1+= q2
84                         q2+= q3;
85                 
86         else:
87                 for a in xrange(steps+1):
88                         pointlist[a][axis] = q0
89                         q0+= q1
90                         q1+= q2
91                         q2+= q3;
92
93 def points_from_bezier_seg(steps, pointlist, radlist, bez1_vec, bez2_vec, radius1, radius2):
94         
95         # x,y,z,axis
96         for ii in (0,1,2):
97                 forward_diff_bezier(bez1_vec[1][ii], bez1_vec[2][ii],  bez2_vec[0][ii], bez2_vec[1][ii], pointlist, steps, ii)
98         
99         # radius - no axis, Copied from blenders BBone roll interpolation.
100         forward_diff_bezier(radius1, radius1 + 0.390464*(radius2-radius1), radius2 - 0.390464*(radius2-radius1),        radius2,        radlist, steps, None)
101
102
103 def debug_pt(co):
104         Blender.Window.SetCursorPos(tuple(co))
105         Blender.Window.RedrawAll()
106         print 'debugging', co
107
108 def freshMesh(mesh):
109         '''
110         Utility function to get a new mesh or clear the existing one, but dont clear everything.
111         '''
112         if mesh:
113                 materials = mesh.materials
114                 mesh.verts = None
115                 for group in mesh.getVertGroupNames():
116                         mesh.removeVertGroup(group) 
117                         
118                 # Add materials back
119                 mesh.materials = materials
120         else:
121                 mesh = bpy.data.meshes.new()
122                 
123         return mesh
124
125 def getObFromName(name):
126         if name:
127                 try:    return bpy.data.objects[name]
128                 except: return None
129         else:
130                 return None
131
132 def getGroupFromName(name):
133         if name:
134                 try:    return bpy.data.groups[name]
135                 except: return None
136         else:
137                 return None     
138
139 def closestVecIndex(vec, vecls):
140         best= -1
141         best_dist = 100000000
142         for i, vec_test in enumerate(vecls):
143                 # Dont use yet, we may want to tho
144                 if vec_test: # Seems odd, but use this so we can disable some verts in the list.
145                         dist = (vec-vec_test).length
146                         if dist < best_dist:
147                                 best = i
148                                 best_dist = dist
149         
150         return best
151
152 IRATIONAL_NUM = 22.0/7.0
153 def next_random_num(rnd):
154         '''
155         return a random number between 0.0 and 1.0
156         '''
157         rnd[0] += (rnd[0] * IRATIONAL_NUM) % 1
158         # prevent 
159         if rnd[0] > 1000000:
160                 rnd[0]-=1000000
161         return rnd[0] % 1
162
163 eul = 0.00001
164
165 BRANCH_TYPE_CURVE = 0
166 BRANCH_TYPE_GROWN = 1
167 BRANCH_TYPE_FILL = 2
168
169 class tree:
170         def __init__(self):
171                 self.branches_all =             []
172                 self.branches_root =    []
173                 self.branches_twigs =   []
174                 self.mesh = None
175                 self.armature = None
176                 self.objectCurve = None
177                 self.objectCurveMat = None
178                 self.objectCurveIMat = None
179                 
180                 self.objectTwigBounds = None # use for twigs only at the moment.
181                 self.objectTwigBoundsIMat = None
182                 self.objectTwigBoundsMat = None
183                 self.objectTwigBoundsMesh = None
184                 
185                 self.objectLeafBounds = None
186                 self.objectLeafBoundsIMat = None
187                 self.objectLeafBoundsMesh = None
188                 
189                 self.limbScale = 1.0
190                 
191                 self.debug_objects = []
192                 self.steps = 6 # defalt, curve overwrites
193         
194         def __repr__(self):
195                 s = ''
196                 s += '[Tree]'
197                 s += '  limbScale: %.6f' % self.limbScale
198                 s += '  object: %s' % self.objectCurve
199                 
200                 for brch in self.branches_root:
201                         s += str(brch)
202                 return s
203         
204         def fromCurve(self, objectCurve):
205                 # Now calculate the normals
206                 self.objectCurve = objectCurve
207                 self.objectCurveMat = objectCurve.matrixWorld
208                 self.objectCurveIMat = self.objectCurveMat.copy().invert()
209                 curve = objectCurve.data
210                 self.steps = curve.resolu # curve resolution
211                 
212                 # Set the curve object scale
213                 if curve.bevob:
214                         # A bit of a hack to guess the size of the curve object if you have one.
215                         bb = curve.bevob.boundingBox
216                         # self.limbScale = (bb[0] - bb[7]).length / 2.825 # THIS IS GOOD WHEN NON SUBSURRFED
217                         self.limbScale = (bb[0] - bb[7]).length / 1.8
218                 elif curve.ext2 != 0.0:
219                         self.limbScale = curve.ext2 * 1.5
220                         
221                 # forward_diff_bezier will fill in the blanks
222                 # nice we can reuse these for every curve segment :)
223                 pointlist = [[None, None, None] for i in xrange(self.steps+1)]
224                 radlist = [ None for i in xrange(self.steps+1) ]
225                 
226                 for spline in curve:
227                         
228                         if len(spline) < 2: # Ignore single point splines
229                                 continue
230                         
231                         if spline.type != 1: # 0 poly, 1 bez, 4 nurbs
232                                 GLOBALS['non_bez_error'] = 1
233                                 continue
234                         
235                                 
236                         brch = branch()
237                         brch.type = BRANCH_TYPE_CURVE
238                         
239                         
240                         
241                         bez_list = list(spline)
242                         for i in xrange(1, len(bez_list)):
243                                 bez1 = bez_list[i-1]
244                                 bez2 = bez_list[i]
245                                 vec1 = bez1.vec
246                                 vec2 = bez2.vec
247                                 if abs(vec1[1][0]-vec2[1][0]) > 0.000001 or\
248                                    abs(vec1[1][1]-vec2[1][1]) > 0.000001 or\
249                                    abs(vec1[1][2]-vec2[1][2]) > 0.000001:
250
251                                         points_from_bezier_seg(self.steps, pointlist, radlist, vec1, vec2, bez1.radius, bez2.radius)
252                                 
253                                         # remove endpoint for all but the last
254                                         len_pointlist = len(pointlist)
255                                         if i != len(bez_list)-1:
256                                                 len_pointlist -= 1
257                                         
258                                         brch.bpoints.extend([ bpoint(brch, Vector(pointlist[ii]), Vector(), radlist[ii] * self.limbScale) for ii in xrange(len_pointlist) ])
259                         
260                         # Finalize once point data is there
261                         if brch.bpoints:
262                                 # if all points are in the same location, this is possible
263                                 self.branches_all.append(brch)
264                                 if brch.bpoints[0].radius < brch.bpoints[-1].radius: # This means we dont have to worry about curve direction.
265                                         brch.bpoints.reverse()
266                                 brch.calcData()
267                         
268                 # Sort from big to small, so big branches get priority
269                 # Py 2.3 dosnt have keywords in sort
270                 try:    self.branches_all.sort( key = lambda brch: -brch.bpoints[0].radius )
271                 except: self.branches_all.sort( lambda brch_a, brch_b: cmp(brch_b.bpoints[0].radius, brch_a.bpoints[0].radius) )
272         
273         
274         def closestBranchPt(self, co):
275                 best_brch = None
276                 best_pt = None
277                 best_dist = 10000000000
278                 for brch in self.branches_all:
279                         for pt in brch.bpoints:
280                                 # if pt.inTwigBounds: # only find twigs, give different results for leaves
281                                 l = (pt.co-co).length
282                                 if l < best_dist:
283                                         best_dist = l
284                                         best_brch = brch
285                                         best_pt = pt
286                 return best_brch, best_pt
287         
288         def setTwigBounds(self, objectMesh):
289                 self.objectTwigBounds = objectMesh
290                 self.objectTwigBoundsMesh = objectMesh.getData(mesh=1)
291                 self.objectTwigBoundsMat = objectMesh.matrixWorld.copy()
292                 self.objectTwigBoundsIMat = self.objectTwigBoundsMat.copy().invert()
293                 
294                 for brch in self.branches_all:
295                         brch.calcTwigBounds(self)
296                         
297         def setLeafBounds(self, objectMesh):
298                 self.objectLeafBounds = objectMesh
299                 self.objectLeafBoundsMesh = objectMesh.getData(mesh=1)
300                 self.objectLeafBoundsIMat = objectMesh.matrixWorld.copy().invert()
301         
302         def isPointInTwigBounds(self, co, selected_only=False):
303                 return self.objectTwigBoundsMesh.pointInside(co * self.objectCurveMat * self.objectTwigBoundsIMat, selected_only)
304
305         def isPointInLeafBounds(self, co, selected_only=False):
306                 return self.objectLeafBoundsMesh.pointInside(co * self.objectCurveMat * self.objectLeafBoundsIMat, selected_only)
307
308         def resetTags(self, value):
309                 for brch in self.branches_all:
310                         brch.tag = value
311         
312         def buildConnections(   self,\
313                                                         sloppy = 1.0,\
314                                                         connect_base_trim = 1.0,\
315                                                         do_twigs = False,\
316                                                         twig_ratio = 2.0,\
317                                                         twig_select_mode = 0,\
318                                                         twig_select_factor = 0.5,\
319                                                         twig_scale = 0.8,\
320                                                         twig_scale_width = 1.0,\
321                                                         twig_random_orientation = 180,\
322                                                         twig_random_angle = 33,\
323                                                         twig_recursive=True,\
324                                                         twig_recursive_limit=3,\
325                                                         twig_ob_bounds=None,\
326                                                         twig_ob_bounds_prune=True,\
327                                                         twig_ob_bounds_prune_taper=1.0,\
328                                                         twig_placement_maxradius=10.0,\
329                                                         twig_placement_maxtwig=0,\
330                                                         twig_follow_parent=0.0,\
331                                                         twig_follow_x=0.0,\
332                                                         twig_follow_y=0.0,\
333                                                         twig_follow_z=0.0,\
334                                                         do_variation = 0,\
335                                                         variation_seed = 1,\
336                                                         variation_orientation = 0.0,\
337                                                         variation_scale = 0.0,\
338                                                         do_twigs_fill = 0,\
339                                                         twig_fill_levels=4,\
340                                                         twig_fill_rand_scale=0.0,\
341                                                         twig_fill_fork_angle_max=180.0,\
342                                                         twig_fill_radius_min=0.1,\
343                                                         twig_fill_radius_factor=0.75,\
344                                                         twig_fill_shape_type=0,\
345                                                         twig_fill_shape_rand=0.0,\
346                                                         twig_fill_shape_power=0.3,\
347                                                 ):
348                 '''
349                 build tree data - fromCurve must run first
350                 '''
351                 
352                 
353                 # Sort the branchs by the first radius, so big branchs get joins first
354                 ### self.branches_all.sort( key = lambda brch: brch.bpoints[0].radius )
355                 
356                 #self.branches_all.reverse()
357                 
358                 # Connect branches
359                 for i in xrange(len(self.branches_all)):
360                         brch_i = self.branches_all[i]
361                         
362                         for j in xrange(len(self.branches_all)):
363                                 if i != j:
364                                         # See if any of the points match this branch
365                                         # see if Branch 'i' is the child of branch 'j'
366                                         
367                                         brch_j = self.branches_all[j]
368                                         
369                                         if not brch_j.inParentChain(brch_i): # So we dont make cyclic tree!
370                                                 
371                                                 pt_best_j, dist = brch_j.findClosest(brch_i.bpoints[0].co)
372                                                 
373                                                 # Check its in range, allow for a bit out - hense the sloppy
374                                                 # The second check in the following IF was added incase the point is close enough to the line but the midpoint is further away
375                                                 # ...in this case the the resulting mesh will be adjusted to fit the join so its best to make it.
376                                                 if      (dist <                                                                                 pt_best_j.radius * sloppy)  or \
377                                                         ((brch_i.bpoints[0].co - pt_best_j.co).length < pt_best_j.radius * sloppy):
378                                                         
379                                                         
380                                                         brch_i.parent_pt = pt_best_j
381                                                         pt_best_j.childCount += 1 # dont remove me
382                                                         
383                                                         brch_i.baseTrim(connect_base_trim)
384                                                         
385                                                         '''
386                                                         if pt_best_j.childCount>4:
387                                                                 raise "ERROR"
388                                                         '''
389                                                         
390                                                         # addas a member of best_j.children later when we have the geometry info available.
391                                                         
392                                                         #### print "Found Connection!!!", i, j
393                                                         break # go onto the next branch
394                 
395                 """
396                         children = [brch_child for brch_child in pt.children]
397                         if children:
398                                 # This pt is one side of the segment, pt.next joins this segment.
399                                 # calculate the median point the 2 segments would spanal
400                                 # Once this is done we need to adjust 2 things
401                                 # 1) move both segments up/down so they match the branches best.
402                                 # 2) set the spacing of the segments around the point.
403                                 
404                 
405                 # First try to get the ideal some space around each joint
406                 # the spacing shoule be an average of 
407                 for brch.bpoints:
408                 """
409                 
410                 '''
411                 for brch in self.branches_all:
412                         brch.checkPointList()
413                 '''
414                 
415                 # Variations - use for making multiple versions of the same tree.
416                 if do_variation:
417                         irational_num = 22.0/7.0 # use to make the random number more odd
418                         rnd = [variation_seed]
419                         
420                         # Add children temporarily
421                         for brch in self.branches_all:
422                                 if brch.parent_pt:
423                                         rnd_rot = ((next_random_num(rnd) * variation_orientation) - 0.5) * 720
424                                         mat_orientation = RotationMatrix(rnd_rot, 3, 'r', brch.parent_pt.no)
425                                         rnd_sca = 1 + ((next_random_num(rnd)-0.5)* variation_scale )
426                                         mat_scale = Matrix([rnd_sca,0,0],[0,rnd_sca,0],[0,0,rnd_sca])
427                                         # mat_orientation = RotationMatrix(0, 3, 'r', brch.parent_pt.no)
428                                         brch.transformRecursive(self, mat_scale * mat_orientation, brch.parent_pt.co)
429                 
430                 if (do_twigs or do_twigs_fill) and twig_ob_bounds: # Only spawn twigs inside this mesh
431                         self.setTwigBounds(twig_ob_bounds)
432                 
433                 # Important we so this with existing parent/child but before connecting and calculating verts.
434                 if do_twigs:
435                         
436                         # scale values down
437                         twig_random_orientation= twig_random_orientation/360.0
438                         twig_random_angle= twig_random_angle/360.0
439                         
440                         irational_num = 22.0/7.0 # use to make the random number more odd
441                         
442                         if not twig_recursive:
443                                 twig_recursive_limit = 0
444                         
445                         self.buildTwigs(twig_ratio, twig_select_mode, twig_select_factor)
446                         
447                         branches_twig_attached = []
448                         
449                         # This wont add all! :/
450                         brch_twig_index = 0
451                         brch_twig_index_LAST = -1 # use this to prevent in inf loop, since its possible we cant place every branch
452                         while brch_twig_index < len(self.branches_twigs) and brch_twig_index_LAST != brch_twig_index:
453                                 ###print "While"
454                                 ### print brch_twig_index, len(self.branches_twigs) # if this dosnt change, quit the while
455                                 
456                                 brch_twig_index_LAST = brch_twig_index
457                                 
458                                 # new twigs have been added, recalculate
459                                 branches_twig_sort = [brch.bestTwigSegment() for brch in self.branches_all]
460                                 branches_twig_sort.sort() # this will sort the branches with best braches for adding twigs to at the start of the list
461                                 
462                                 for tmp_sortval, twig_pt_index, brch_parent in branches_twig_sort: # tmp_sortval is not used.
463                                         if              twig_pt_index != -1 and \
464                                                         (twig_recursive_limit == 0 or brch_parent.generation < twig_recursive_limit) and \
465                                                         (twig_placement_maxtwig == 0 or brch_parent.twig_count < twig_placement_maxtwig) and \
466                                                         brch_parent.bpoints[twig_pt_index].radius < twig_placement_maxradius:
467                                                 
468                                                 if brch_twig_index >= len(self.branches_twigs):
469                                                         break
470                                                 
471                                                 brch_twig = self.branches_twigs[brch_twig_index]
472                                                 parent_pt = brch_parent.bpoints[twig_pt_index]
473                                                 
474                                                 brch_twig.parent_pt = parent_pt
475                                                 parent_pt.childCount += 1
476                                                 
477                                                 # Scale this twig using this way...
478                                                 # The size of the parent, scaled by the parent point's radius,
479                                                 # ...compared to the parent branch;s root point radius.
480                                                 # Also take into account the length of the parent branch
481                                                 # Use this for pretend random numbers too.
482                                                 scale = twig_scale * (parent_pt.branch.bpoints[0].radius / brch_twig.bpoints[0].radius) * (parent_pt.radius / parent_pt.branch.bpoints[0].radius)
483                                                 
484                                                 # Random orientation
485                                                 # THIS IS NOT RANDOM - Dont be real random so we can always get re-produceale results.
486                                                 if twig_random_orientation:     rnd1 = (((irational_num * scale * 10000000) % 360) - 180) * twig_random_orientation
487                                                 else:                                           rnd1 = 0.0
488                                                 if twig_random_angle:           rnd2 = (((irational_num * scale * 66666666) % 360) - 180) * twig_random_angle
489                                                 else:                                           rnd2 = 0.0
490                                                 
491                                                 # Align this with the existing branch
492                                                 angle = AngleBetweenVecsSafe(zup, parent_pt.no)
493                                                 cross = CrossVecs(zup, parent_pt.no)
494                                                 mat_align = RotationMatrix(angle, 3, 'r', cross)
495                                                 
496                                                 # Use the bend on the point to work out which way to make the branch point!
497                                                 if parent_pt.prev:      cross = CrossVecs(parent_pt.no, parent_pt.prev.no - parent_pt.no)
498                                                 else:                           cross = CrossVecs(parent_pt.no, parent_pt.next.no - parent_pt.no)
499                                                 
500                                                 if parent_pt.branch.parent_pt:
501                                                         angle = AngleBetweenVecsSafe(parent_pt.branch.parent_pt.no, parent_pt.no)
502                                                 else:
503                                                         # Should add a UI for this... only happens when twigs come off a root branch
504                                                         angle = 66
505                                                 
506                                                 mat_branch_angle = RotationMatrix(angle+rnd1, 3, 'r', cross)
507                                                 mat_scale = Matrix([scale,0,0],[0,scale,0],[0,0,scale])
508                                                 
509                                                 mat_orientation = RotationMatrix(rnd2, 3, 'r', parent_pt.no)
510                                                 
511                                                 if twig_scale_width != 1.0:
512                                                         # adjust length - no radius adjusting
513                                                         for pt in brch_twig.bpoints:
514                                                                 pt.radius *= twig_scale_width
515                                                 
516                                                 brch_twig.transform(mat_scale * mat_branch_angle * mat_align * mat_orientation, parent_pt.co)
517                                                 
518                                                 # Follow the parent normal
519                                                 if twig_follow_parent or twig_follow_x or twig_follow_y or twig_follow_z:
520                                                         
521                                                         vecs = []
522                                                         brch_twig_len = float(len(brch_twig.bpoints))
523                                                         
524                                                         if twig_follow_parent:
525                                                                 no = parent_pt.no.copy() * twig_follow_parent
526                                                         else:
527                                                                 no = Vector()
528                                                         
529                                                         no.x += twig_follow_x
530                                                         no.y += twig_follow_y
531                                                         no.z += twig_follow_z
532                                                         
533                                                         for i, pt in enumerate(brch_twig.bpoints):
534                                                                 if pt.prev:
535                                                                         fac = i / brch_twig_len
536                                                                         
537                                                                         # Scale this value
538                                                                         fac_inv = 1-fac
539                                                                         
540                                                                         no_orig = pt.co - pt.prev.co
541                                                                         len_orig = no_orig.length
542                                                                         
543                                                                         no_new = (fac_inv * no_orig) + (fac * no)
544                                                                         no_new.length = len_orig
545                                                                         
546                                                                         # Mix the 2 normals
547                                                                         vecs.append(no_new)
548                                                                         
549                                                         # Apply the coords
550                                                         for i, pt in enumerate(brch_twig.bpoints):
551                                                                 if pt.prev:
552                                                                         pt.co = pt.prev.co + vecs[i-1]
553                                                         
554                                                         brch_twig.calcPointExtras()
555                                                 
556                                                 
557                                                 # When using a bounding mesh, clip and calculate points in bounds.
558                                                 #print "Attempting to trim base"
559                                                 brch_twig.baseTrim(connect_base_trim)
560                                                 
561                                                 if twig_ob_bounds and (twig_ob_bounds_prune or twig_recursive):
562                                                         brch_twig.calcTwigBounds(self)
563                                                 
564                                                         # we would not have been but here if the bounds were outside
565                                                         if twig_ob_bounds_prune:
566                                                                 brch_twig.boundsTrim()
567                                                                 if twig_ob_bounds_prune_taper != 1.0:
568                                                                         # taper to a point. we could use some nice taper algo here - just linear atm.
569                                                                         
570                                                                         brch_twig.taper(twig_ob_bounds_prune_taper)
571                                                 
572                                                 # Make sure this dosnt mess up anything else
573                                                 
574                                                 brch_twig_index += 1
575                                                 
576                                                 # Add to the branches
577                                                 #self.branches_all.append(brch_twig)
578                                                 if len(brch_twig.bpoints) > 2:
579                                                         branches_twig_attached.append(brch_twig)
580                                                         brch_twig.generation = brch_parent.generation + 1
581                                                         brch_parent.twig_count += 1
582                                                 else:
583                                                         # Dont add the branch
584                                                         parent_pt.childCount -= 1
585                                 
586                                 # Watch This! - move 1 tab down for no recursive twigs
587                                 if twig_recursive:
588                                         self.branches_all.extend(branches_twig_attached)
589                                         branches_twig_attached = []
590                         
591                         if not twig_recursive:
592                                 self.branches_all.extend(branches_twig_attached)
593                                 branches_twig_attached = []
594                 
595                 
596                 if do_twigs_fill and twig_ob_bounds:
597                         self.twigFill(\
598                                 twig_fill_levels,\
599                                 twig_fill_rand_scale,\
600                                 twig_fill_fork_angle_max,\
601                                 twig_fill_radius_min,\
602                                 twig_fill_radius_factor,\
603                                 twig_fill_shape_type,\
604                                 twig_fill_shape_rand,\
605                                 twig_fill_shape_power,\
606                         )
607                 
608                 ### self.branches_all.sort( key = lambda brch: brch.parent_pt != None )
609                 
610                 # Calc points with dependancies
611                 # detect circular loops!!! - TODO
612                 #### self.resetTags(False) # NOT NEEDED NOW
613                 done_nothing = False
614                 while done_nothing == False:
615                         done_nothing = True
616                         
617                         for brch in self.branches_all:
618                                 
619                                 if brch.tag == False and (brch.parent_pt == None or brch.parent_pt.branch.tag == True):
620                                         # Assign this to a spesific side of the parents point
621                                         # we know this is a child but not which side it should be attached to.
622                                         if brch.parent_pt:
623                                                 
624                                                 child_locs = [\
625                                                 brch.parent_pt.childPointUnused(0),\
626                                                 brch.parent_pt.childPointUnused(1),\
627                                                 brch.parent_pt.childPointUnused(2),\
628                                                 brch.parent_pt.childPointUnused(3)]
629                                                 
630                                                 best_idx = closestVecIndex(brch.bpoints[0].co, child_locs)
631                                                 
632                                                 # best_idx could be -1 if all childPoint's are used however we check for this and dont allow it to happen.
633                                                 #if best_idx==-1:
634                                                 #       raise "Error"z
635                                                 brch.parent_pt.children[best_idx] = brch
636                                         
637                                         for pt in brch.bpoints:
638                                                 pt.calcVerts()
639                                         
640                                         done_nothing = False
641                                         brch.tag = True
642                 
643                 '''
644                 for i in xrange(len(self.branches_all)):
645                         brch_i = self.branches_all[i]
646                         print brch_i.myindex,
647                         print 'tag', brch_i.tag,
648                         print 'parent is',
649                         if brch_i.parent_pt:
650                                 print brch_i.parent_pt.branch.myindex
651                         else:
652                                 print None
653                 '''
654         
655         def optimizeSpacing(self, seg_density=0.5, seg_density_angle=20.0, seg_density_radius=0.3, joint_compression=1.0, joint_smooth=1.0):
656                 '''
657                 Optimize spacing, taking branch hierarchy children into account,
658                 can add or subdivide segments so branch joins dont look horrible.
659                 '''
660                 for brch in self.branches_all:
661                         brch.evenJointDistrobution(joint_compression)
662                 
663                 # Correct points that were messed up from sliding
664                 # This happens when one point is pushed past another and the branch gets an overlaping line
665                 
666                 for brch in self.branches_all:
667                         brch.fixOverlapError(joint_smooth)
668                 
669                 
670                 # Collapsing
671                 for brch in self.branches_all:
672                         brch.collapsePoints(seg_density, seg_density_angle, seg_density_radius, joint_smooth)
673                         
674                 '''
675                 for brch in self.branches_all:
676                         brch.branchReJoin()
677                 '''
678         
679         def twigFill(self_tree,\
680                         twig_fill_levels,\
681                         twig_fill_rand_scale,\
682                         twig_fill_fork_angle_max,\
683                         twig_fill_radius_min,\
684                         twig_fill_radius_factor,\
685                         twig_fill_shape_type,\
686                         twig_fill_shape_rand,\
687                         twig_fill_shape_power,\
688                 ):
689                 '''
690                 Fill with twigs, this function uses its own class 'segment'
691                 
692                 twig_fill_shape_type;
693                         0 - no child smoothing
694                         1 - smooth one child
695                         2 - smooth both children
696                 
697                 '''
698                 
699                 rnd = [1]
700                 
701                 segments_all = []
702                 segments_level = []
703                 
704                 # Only for testing
705                 def preview_curve():
706                         TWIG_WIDTH_MAX = 1.0
707                         TWIG_WIDTH_MIN = 0.1
708                         cu = bpy.data.curves["cu"]
709                         # remove all curves
710                         while len(cu):
711                                 del cu[0]
712                         # return
713                         
714                         cu.setFlag(1)
715                         cu.ext2 = 0.01
716                         
717                         WIDTH_STEP = (TWIG_WIDTH_MAX-TWIG_WIDTH_MIN) / twig_fill_levels
718                         
719                         for i, seg in enumerate(segments_all):
720                                 
721                                 # 1 is the base and 2 is the tail
722                                 
723                                 p1_h2 = seg.getHeadHandle() # isnt used
724                                 p1_co = seg.headCo
725                                 p1_h1 = seg.getHeadHandle()
726                                 
727                                 p2_h1 = seg.getTailHandle()
728                                 
729                                 p2_co = seg.tailCo
730                                 p2_h2 = seg.tailCo # isnt used
731                                 
732                                 bez1 = Blender.BezTriple.New([ p1_h1[0], p1_h1[1], p1_h1[2], p1_co[0], p1_co[1], p1_co[2], p1_h2[0], p1_h2[1], p1_h2[2] ])
733                                 bez2 = Blender.BezTriple.New([ p2_h1[0], p2_h1[1], p2_h1[2], p2_co[0], p2_co[1], p2_co[2], p2_h2[0], p2_h2[1], p2_h2[2] ])
734                                 bez1.handleTypes = bez2.handleTypes = [Blender.BezTriple.HandleTypes.FREE, Blender.BezTriple.HandleTypes.FREE]
735                                 
736                                 bez1.radius = TWIG_WIDTH_MIN + (WIDTH_STEP * (seg.levelFromLeaf+1))
737                                 bez2.radius = TWIG_WIDTH_MIN + (WIDTH_STEP * seg.levelFromLeaf)
738                                 
739                                 cunurb = cu.appendNurb(bez1)
740                                 cunurb.append(bez2)
741                                 
742                                 # This sucks
743                                 for bez in cunurb:
744                                         bez.handleTypes = [Blender.BezTriple.HandleTypes.FREE, Blender.BezTriple.HandleTypes.FREE]
745                         
746                         ### cc = sce.objects.new( cu )
747                         cu.update()
748                 
749                 
750                 def mergeCo(parentCo, ch1Co, ch2Co, twig_fill_shape_rand):
751                         if twig_fill_shape_rand==0.0:
752                                 return (parentCo + ch1Co + ch2Co) / 3.0
753                         else:
754                                 
755                                 w1 = (next_random_num(rnd)*twig_fill_shape_rand) + (1-twig_fill_shape_rand)
756                                 w2 = (next_random_num(rnd)*twig_fill_shape_rand) + (1-twig_fill_shape_rand)
757                                 w3 = (next_random_num(rnd)*twig_fill_shape_rand) + (1-twig_fill_shape_rand)
758                                 wtot = w1+w2+w3
759                                 w1=w1/wtot
760                                 w2=w2/wtot
761                                 w3=w3/wtot
762                                 
763                                 # return (parentCo*w1 + ch1Co*w2 + ch2Co*w2)
764                                 co1 = (parentCo * w1)   + (ch1Co * (1.0-w1))
765                                 co2 = (ch1Co * w2)              + (ch2Co * (1.0-w2))
766                                 co3 = (ch2Co * w3)              + (parentCo * (1.0-w3))
767                                 
768                                 return (co1 + co2 + co3) / 3.0
769                                 
770                                 
771                 
772                 class segment:
773                         def __init__(self, level):
774                                 self.headCo = Vector()
775                                 self.tailCo = Vector()
776                                 self.parent = None
777                                 self.mergeCount = 0
778                                 self.levelFromLeaf = level # how far we are from the leaf in levels
779                                 self.levelFromRoot = -1 # set later, assume root bone
780                                 self.children = []
781                                 segments_all.append(self)
782                                 
783                                 if level >= len(segments_level):        segments_level.append([self])
784                                 else:                                                           segments_level[level].append(self)
785                                 
786                                 self.brothers = []
787                                 self.no = Vector() # only endpoints have these
788                                 # self.id = len(segments_all)
789                                 
790                                 # First value is the bpoint,
791                                 # Second value is what to do -
792                                 #  0 - dont join
793                                 #  1 - Join to parent (tree point)
794                                 #  2 - join to parent, point from another fill-twig branch we just created.
795                                 
796                                 self.bpt = (None, False) # branch point for root segs only
797                                 self.new_bpt = None
798                                 
799                                 self.used = False # use this to tell if we are apart of a branch
800                         
801                         def sibling(self):
802                                 i = self.parent.children.index(self)
803                                 
804                                 if i == 0:
805                                         return self.parent.children[ 1 ]
806                                 elif i == 1:
807                                         return self.parent.children[ 0 ]
808                                 else:
809                                         raise "error"
810                                         
811                         
812                         def getHeadHandle(self):
813                                 """
814                                 For Bezier only
815                                 """
816                                 
817                                 if not self.parent:
818                                         return self.headCo
819                                 
820                                 if twig_fill_shape_type == 0: # no smoothing
821                                         return self.headCo
822                                 elif twig_fill_shape_type == 1:
823                                         if self.parent.children[1] == self:
824                                                 return self.headCo
825                                 # 2 - always do both
826                                 
827                                 
828                                 # Y shape with curve? optional
829                                 
830                                 # we have a parent but it has no handle direction, easier
831                                 if not self.parent.parent:      no = self.parent.headCo - self.parent.tailCo
832                                 else:                                           no = self.parent.parent.headCo-self.parent.tailCo
833                                 
834                                 no.length =  self.getLength() * twig_fill_shape_power
835                                 # Ok we have to account for the parents handle
836                                 return self.headCo - no
837                                 # return self.headCo - Vector(1, 0,0)
838                         
839                         def getTailHandle(self):
840                                 """
841                                 For Bezier only
842                                 """
843                                 if self.parent:
844                                         no = self.parent.headCo-self.tailCo
845                                         no.length = self.getLength() * twig_fill_shape_power
846                                         return self.tailCo + no
847                                 else:
848                                         return self.tailCo # isnt used
849                         
850                         def getRootSeg(self):
851                                 seg = self
852                                 while seg.parent:
853                                         seg = seg.parent
854                                 
855                                 return seg
856                         
857                         def calcBrothers(self):
858                                 # Run on children first
859                                 self.brothers.extend( \
860                                         [seg_child_sibling.parent \
861                                                 for seg_child in self.children \
862                                                 for seg_child_sibling in seg_child.brothers \
863                                                 if seg_child_sibling.parent not in (self, None)]\
864                                         )
865                                         #print self.brothers
866                         
867                         def calcLevelFromRoot(self):
868                                 if self.parent:
869                                         self.levelFromRoot = self.parent.levelFromRoot + 1
870                                 
871                                 for seg_child in self.children:
872                                         seg_child.calcLevelFromRoot()
873                                         
874                         # Dont use for now, but scale worked, transform was never tested.
875                         """
876                         def transform(self, matrix):
877                                 self.headCo = self.headCo * matrix
878                                 self.tailCo = self.tailCo * matrix
879                                 
880                                 if self.children:
881                                         ch1 = self.children[0]
882                                         ch2 = self.children[1]
883                                         
884                                         ch1.transform(matrix)
885                                         ch2.transform(matrix)
886                         
887                         def scale(self, scale, cent=None):
888                                 # scale = 0.9
889                                 #matrix = Matrix([scale,0,0],[0,scale,0],[0,0,scale]).resize4x4()
890                                 #self.transform(matrix)
891                                 if cent == None: # first iter
892                                         cent = self.headCo
893                                         self.tailCo = ((self.tailCo-cent) * scale) + cent
894                                 else:
895                                         self.headCo = ((self.headCo-cent) * scale) + cent
896                                         self.tailCo = ((self.tailCo-cent) * scale) + cent
897                                 
898                                 if self.children:
899                                         self.children[0].scale(scale, cent)
900                                         self.children[1].scale(scale, cent)
901                         """
902                         def recalcChildLoc(self):
903                                 if not self.children:
904                                         return
905                                 ch1 = self.children[0]
906                                 ch2 = self.children[1]
907                                 new_mid = mergeCo(self.headCo, ch1.tailCo, ch2.tailCo, twig_fill_shape_rand)
908                                 
909                                 self.tailCo[:] = ch1.headCo[:] = ch2.headCo[:] = new_mid
910                                 
911                                 ch1.recalcChildLoc()
912                                 ch2.recalcChildLoc()
913                         
914                         def merge(self, other):
915                                 """
916                                 Merge other into self and make a new segment
917                                 """
918                                 """
919                                 seg_child = segment(self.levelFromLeaf)
920                                 self.levelFromLeaf += 1
921                                 
922                                 seg_child.parent = other.parent = self
923                                 
924                                 # No need, recalcChildLoc sets the other coords
925                                 #self.parent.tailCo = (self.headCo + self.tailCo + other.tailCo) / 3.0
926                                 #self.parent.headCo[:] = self.headCo
927                                 
928                                 seg_child.headCo[:] = self.headCo
929                                 
930                                 # isect = LineIntersect(self.headCo, self.tailCo, other.headCo, other.tailCo)
931                                 # new_head = (isect[0]+isect[1]) * 0.5
932                                 
933                                 seg_child.mergeCount += 1
934                                 other.mergeCount += 1
935                                 
936                                 self.children.extend([ seg_child, other ])
937                                 
938                                 self.recalcChildLoc()
939                                 
940                                 # print 'merging', self.id, other.id
941                                 """
942                                 
943                                 #new_head = (self.headCo + self.tailCo + other.headCo + other.tailCo) * 0.25
944                                 
945                                 self.parent = other.parent = segment(self.levelFromLeaf + 1)
946                                 
947                                 # No need, recalcChildLoc sets the self.parent.tailCo
948                                 # self.parent.tailCo = (self.headCo + self.tailCo + other.tailCo) / 3.0
949                                 
950                                 self.parent.headCo[:] = self.headCo
951                                 self.parent.bpt = self.bpt
952                                 self.bpt = (None, False)
953                                 
954                                 # isect = LineIntersect(self.headCo, self.tailCo, other.headCo, other.tailCo)
955                                 # new_head = (isect[0]+isect[1]) * 0.5
956                                 
957                                 self.mergeCount += 1
958                                 other.mergeCount += 1
959                                 
960                                 self.parent.children.extend([ self, other ])
961                                 
962                                 self.parent.recalcChildLoc()
963                                 # print 'merging', self.id, other.id
964                                 
965                                 
966                         def findBestMerge(self, twig_fill_fork_angle_max):
967                                 # print "findBestMerge"
968                                 if self.parent != None:
969                                         return
970                                 
971                                 best_dist = 1000000
972                                 best_seg = None
973                                 for seg_list in (self.brothers, segments_level[self.levelFromLeaf]):
974                                         #for seg_list in (segments_level[self.levelFromLeaf],):
975                                         
976                                         # only use all other segments if we cant find any from our brothers
977                                         if seg_list == segments_level[self.levelFromLeaf] and best_seg != None:
978                                                 break
979                                         
980                                         for seg in seg_list:
981                                                 # 2 ppoint join 
982                                                 if seg != self and seg.mergeCount == 0 and seg.parent == None:
983                                                         
984                                                         # find the point they would join        
985                                                         test_dist = (self.tailCo - seg.tailCo).length
986                                                         if test_dist < best_dist:
987                                                                 if twig_fill_fork_angle_max > 179:
988                                                                         best_dist = test_dist
989                                                                         best_seg = seg
990                                                                 else:
991                                                                         # Work out if the desired angle range is ok.
992                                                                         mco = mergeCo( self.headCo, self.tailCo, seg.tailCo, 0.0 ) # we dont want the random value for this test
993                                                                         ang = AngleBetweenVecsSafe(self.tailCo-mco, seg.tailCo-mco)
994                                                                         if ang < twig_fill_fork_angle_max:
995                                                                                 best_dist = test_dist
996                                                                                 best_seg = seg
997                                 return best_seg
998                         
999                         def getNormal(self):
1000                                 return (self.headCo - self.tailCo).normalize()
1001                         
1002                         def getLength(self):
1003                                 return (self.headCo - self.tailCo).length
1004                         """
1005                         def toMatrix(self, LEAF_SCALE, LEAF_RANDSCALE, LEAF_RANDVEC):
1006                                 if LEAF_RANDSCALE:      scale = LEAF_SCALE * Rand(1.0-LEAF_RANDSCALE, 1.0+LEAF_RANDSCALE)
1007                                 else:                           scale = LEAF_SCALE * 1.0
1008                                 
1009                                 if LEAF_RANDVEC:        rand_vec = Vector( Rand(-1, 1), Rand(-1, 1), Rand(-1, 1) ).normalize() * LEAF_RANDVEC
1010                                 else:                           rand_vec = Vector( )
1011                                 
1012                                 return Matrix([scale,0,0],[0,scale,0],[0,0,scale]).resize4x4() * (self.no + rand_vec).toTrackQuat('x', 'z').toMatrix().resize4x4() * TranslationMatrix(self.tailCo)
1013                         """
1014                 def distripute_seg_on_mesh(me__, face_group):
1015                         """
1016                         add segment endpoints
1017                         """
1018                         
1019                         vert_segment_mapping = {}
1020                         for f in face_group:
1021                                 for v in f:
1022                                         i = v.index
1023                                         if i not in vert_segment_mapping:
1024                                                 vert_segment_mapping[i] = len(segments_all)
1025                                                 v.sel = True
1026                                                 seg = segment(0)
1027                                                 # seg.tailCo = v.co.copy() # headCo undefined atm.
1028                                                 seg.tailCo = v.co.copy() * self_tree.objectTwigBoundsMat * self_tree.objectCurveIMat
1029                                                 
1030                                                 # self_tree.objectCurveMat
1031                                                 
1032                                                 seg.no = v.no
1033                         
1034                         # Build connectivity
1035                         for ed in me__.edges:
1036                                 if ed.v1.sel and ed.v2.sel:
1037                                         i1,i2 = ed.key
1038                                         i1 = vert_segment_mapping[i1]
1039                                         i2 = vert_segment_mapping[i2]
1040                                         
1041                                         segments_all[i1].brothers.append( segments_all[i2] )
1042                                         segments_all[i2].brothers.append( segments_all[i1] )
1043                         
1044                         # Dont need to return anything, added when created.
1045                 
1046                 def set_seg_attach_point(seg, interior_points, twig_fill_rand_scale):
1047                         """
1048                         Can only run on end nodes that have normals set
1049                         """
1050                         best_dist = 1000000000.0
1051                         best_point = None
1052                         
1053                         co = seg.tailCo
1054                         
1055                         for pt in interior_points:
1056                                 # line from the point to the seg endpoint
1057                                 
1058                                 line_normal = seg.tailCo - pt.nextMidCo
1059                                 l = line_normal.length
1060                                 
1061                                 
1062                                 cross1 = CrossVecs( seg.no, line_normal )
1063                                 cross2 = CrossVecs( pt.no, line_normal )
1064                                 
1065                                 angle_line = min(AngleBetweenVecsSafe(cross1, cross2), AngleBetweenVecsSafe(cross1, -cross2))
1066                                 angle_leaf_no_diff = min(AngleBetweenVecsSafe(line_normal, seg.no), AngleBetweenVecsSafe(line_normal, -seg.no))
1067                                 
1068                                 # BEST_ANG=66.0
1069                                 # angle = 66.0 # min(AngleBetweenVecs(v2_co-v1_co, leaf.co-cc), AngleBetweenVecs(v1_co-v2_co, leaf.co-cc))
1070                                 # print angle, angle2
1071                                 # l = (l * ((1+abs(angle-BEST_ANG))**2 )) / (1+angle_line)
1072                                 l = (1+(angle_leaf_no_diff/180)) * (1+(angle_line/180)) * l
1073                                 
1074                                 if l < best_dist:
1075                                         best_pt = pt
1076                                         best_co = pt.nextMidCo
1077                                         
1078                                         best_dist = l
1079         
1080                         # twig_fill_rand_scale
1081                         seg.headCo = best_co.copy()
1082                         
1083                         if twig_fill_rand_scale:
1084                                 seg_dir = seg.tailCo - seg.headCo
1085                                 
1086                                 seg_dir.length = seg_dir.length * ( 1.0 - (next_random_num(rnd)*twig_fill_rand_scale) )
1087                                 seg.tailCo = seg.headCo + seg_dir
1088                         
1089                         
1090                         if best_pt.childCount < 4:
1091                                 # Watch this!!! adding a user before its attached and the branch is created!
1092                                 # make sure if its not added later on, this isnt left added
1093                                 best_pt.childCount += 1
1094                                 
1095                                 # True/False denotes weather we try to connect to our parent branch
1096                                 seg.bpt = (best_pt, True)
1097                         else:
1098                                 seg.bpt = (best_pt, False)
1099                                 
1100                         return True
1101
1102
1103                 # END Twig code, next add them
1104                 
1105                 
1106                 """
1107                 Uses a reversed approch, fill in twigs from a bounding mesh
1108                 """
1109                 # print "twig_fill_fork_angle_max"
1110                 # twig_fill_fork_angle_max = 60.0 # 
1111                 # forward_diff_bezier will fill in the blanks
1112                 # nice we can reuse these for every curve segment :)
1113                 pointlist = [[None, None, None] for i in xrange(self_tree.steps+1)]
1114                 radlist = [ None for i in xrange(self_tree.steps+1) ]
1115                 
1116                 orig_branch_count = len(self_tree.branches_all)
1117                 
1118                 for face_group in BPyMesh.mesh2linkedFaces(self_tree.objectTwigBoundsMesh):
1119                         # Set the selection to do point inside.
1120                         self_tree.objectTwigBoundsMesh.sel = False
1121                         for f in face_group: f.sel = True
1122                         
1123                         interior_points = []
1124                         interior_normal = Vector()
1125                         for i, brch in enumerate(self_tree.branches_all):
1126                                 
1127                                 if i == orig_branch_count:
1128                                         break # no need to check new branches are inside us
1129                                         
1130                                 for pt in brch.bpoints:
1131                                         if pt.next and pt.childCount < 4: # cannot attach to the last points
1132                                                 if self_tree.isPointInTwigBounds(pt.co, True): # selected_only
1133                                                         interior_points.append(pt)
1134                                                         interior_normal += pt.no * pt.radius
1135                         
1136                         segments_all[:] = []
1137                         segments_level[:] = []
1138                         
1139                         if interior_points:
1140                                 # Ok, we can add twigs now
1141                                 distripute_seg_on_mesh( self_tree.objectTwigBoundsMesh, face_group )
1142                                 
1143                                 for seg in segments_level[0]: # only be zero segments
1144                                         # Warning, increments the child count for bpoints we attach to!!
1145                                         set_seg_attach_point(seg, interior_points, twig_fill_rand_scale)
1146                                 
1147                                 # Try sorting by other properties! this is ok for now
1148                                 for segments_level_current in segments_level:
1149                                         segments_level_current.sort( key = lambda seg:  -(seg.headCo-seg.tailCo).length )
1150                                 
1151                                 for level in xrange(twig_fill_levels):
1152                                         if len(segments_level) > level:
1153                                                 for seg in segments_level[level]:
1154                                                         # print level, seg.brothers
1155                                                         if seg.mergeCount == 0:
1156                                                                 seg_merge = seg.findBestMerge(twig_fill_fork_angle_max)
1157                                                                 if seg_merge:
1158                                                                         seg.merge( seg_merge )
1159                                         
1160                                         if len(segments_level) > level+1:
1161                                                 for seg in segments_level[level+1]:
1162                                                         seg.calcBrothers()
1163                                 
1164                                 for seg in segments_all:
1165                                         if seg.parent == None:
1166                                                 seg.levelFromRoot = 0
1167                                                 seg.calcLevelFromRoot()
1168                                 
1169                                 '''
1170                                 for i, seg in enumerate(segments_all):  
1171                                         # Make a branch from this data!
1172                                         
1173                                         brch = branch()
1174                                         brch.type = BRANCH_TYPE_FILL
1175                                         self_tree.branches_all.append(brch)
1176                                         
1177                                         # ============================= do this per bez pair
1178                                         # 1 is the base and 2 is the tail
1179                                         
1180                                         #p1_h1 = seg.getHeadHandle()
1181                                         p1_co = seg.headCo.copy()
1182                                         p1_h2 = seg.getHeadHandle() # isnt used
1183                                         
1184                                         p2_h1 = seg.getTailHandle()
1185                                         p2_co = seg.tailCo.copy()
1186                                         #p2_h2 = seg.getTailHandle() # isnt used
1187                                         
1188                                         
1189                                         bez1_vec = (None, p1_co, p1_h2)
1190                                         bez2_vec = (p2_h1, p2_co, None)
1191                                         
1192                                         seg_root = seg.getRootSeg()
1193                                         
1194                                         radius_root = seg_root.bpt.radius * twig_fill_radius_factor
1195                                         # Clamp so the head is never smaller then the tail
1196                                         if radius_root < twig_fill_radius_min: radius_root = twig_fill_radius_min
1197                                                 
1198                                         if seg_root.levelFromLeaf:
1199                                                 # print seg_root.levelFromLeaf, seg.levelFromRoot
1200                                                 WIDTH_STEP = (radius_root - twig_fill_radius_min) / (seg_root.levelFromLeaf+1)
1201                                                 
1202                                                 radius1 = twig_fill_radius_min + (WIDTH_STEP * (seg.levelFromLeaf+1))
1203                                                 if seg.levelFromLeaf:   radius2 = twig_fill_radius_min + (WIDTH_STEP * seg.levelFromLeaf)
1204                                                 else:                                   radius2 = twig_fill_radius_min
1205                                         else:
1206                                                 radius1 = radius_root
1207                                                 radius2 = twig_fill_radius_min 
1208                                         
1209                                         
1210                                         points_from_bezier_seg(self_tree.steps, pointlist, radlist, bez1_vec, bez2_vec, radius1, radius2)
1211                                         
1212                                         # dont apply self_tree.limbScale here! - its alredy done
1213                                         bpoints = [ bpoint(brch, Vector(pointlist[ii]), Vector(), radlist[ii]) for ii in xrange(len(pointlist)) ]
1214                                         
1215                                         # remove endpoint for all but the last
1216                                         #if i != len(bez_list)-1:
1217                                         #       bpoints.pop()
1218                                         
1219                                         brch.bpoints.extend(bpoints)
1220                                         # =============================
1221                                         
1222                                         # Finalize once point data is there
1223                                         brch.calcData()
1224                                 #
1225                                 #preview_curve()
1226                                 '''
1227                         
1228                                 for segments_level_current in reversed(segments_level):
1229                                         for seg in segments_level_current:
1230                                                 if seg.used == False and (seg.parent == None or seg.parent.used == True):
1231                                                         
1232                                                         # The root segment for this set of links.
1233                                                         # seg_root_linked = seg
1234                                                         
1235                                                         brch = branch()
1236                                                         brch.type = BRANCH_TYPE_FILL
1237                                                         self_tree.branches_all.append(brch)
1238                                                         
1239                                                         # Can we attach to a real branch?
1240                                                         if seg.parent == None:
1241                                                                 if seg.bpt[1]: # we can do a real join into the attach point
1242                                                                         brch.parent_pt = seg.bpt[0]
1243                                                                         # brch.parent_pt.childCount # this has alredy changed from 
1244                                                         
1245                                                         '''
1246                                                         if seg.parent:
1247                                                                 if seg.bpt[1] == 2:
1248                                                                         #if seg.bpt[1]:
1249                                                                         # print "Making Connection"
1250                                                                         if seg.bpt[0] == None:
1251                                                                                 raise "Error"
1252                                                                         if seg.bpt[1] != 2:
1253                                                                                 print seg.bpt[1]
1254                                                                                 raise "Error"
1255                                                                         
1256                                                                         brch.parent_pt = seg.bpt[1]
1257                                                                         brch.parent_pt.childCount += 1
1258                                                                         if brch.parent_pt.childCount > 4:
1259                                                                                 raise "Aeeae"
1260                                                                         print "\n\nM<aking Joint!!"
1261                                                         '''
1262                                                         
1263                                                         if seg.parent:
1264                                                                 sibling = seg.sibling()
1265                                                                 if sibling.new_bpt:
1266                                                                         if sibling.new_bpt.childCount < 4:
1267                                                                                 brch.parent_pt = sibling.new_bpt
1268                                                                                 brch.parent_pt.childCount +=1
1269                                                         
1270                                                         # Go down the hierarhy
1271                                                         is_first = True
1272                                                         while seg != None:
1273                                                                 seg.used = True
1274                                                                 
1275                                                                 # ==============================================
1276                                                                 
1277                                                                 #p1_h1 = seg.getHeadHandle()
1278                                                                 p1_co = seg.headCo.copy()
1279                                                                 p1_h2 = seg.getHeadHandle() # isnt used
1280                                                                 
1281                                                                 p2_h1 = seg.getTailHandle()
1282                                                                 p2_co = seg.tailCo.copy()
1283                                                                 #p2_h2 = seg.getTailHandle() # isnt used
1284                                                                 
1285                                                                 
1286                                                                 bez1_vec = (None, p1_co, p1_h2)
1287                                                                 bez2_vec = (p2_h1, p2_co, None)
1288                                                                 
1289                                                                 seg_root = seg.getRootSeg()
1290                                                                 
1291                                                                 radius_root = seg_root.bpt[0].radius * twig_fill_radius_factor
1292                                                                 # Clamp so the head is never smaller then the tail
1293                                                                 if radius_root < twig_fill_radius_min: radius_root = twig_fill_radius_min
1294                                                                         
1295                                                                 if seg_root.levelFromLeaf:      
1296                                                                         # print seg_root.levelFromLeaf, seg.levelFromRoot
1297                                                                         widthStep = (radius_root - twig_fill_radius_min) / (seg_root.levelFromLeaf+1)
1298                                                                         
1299                                                                         radius1 = twig_fill_radius_min + (widthStep * (seg.levelFromLeaf+1))
1300                                                                         if seg.levelFromLeaf:   radius2 = twig_fill_radius_min + (widthStep * seg.levelFromLeaf)
1301                                                                         else:                                   radius2 = twig_fill_radius_min
1302                                                                 else:
1303                                                                         radius1 = radius_root
1304                                                                         radius2 = twig_fill_radius_min 
1305                                                                 
1306                                                                 points_from_bezier_seg(self_tree.steps, pointlist, radlist, bez1_vec, bez2_vec, radius1, radius2)
1307                                                                 
1308                                                                 
1309                                                                 start_pointlist = 0
1310                                                                 
1311                                                                 # This is like baseTrim, (remove the base points to make nice joins, accounting for radius of parent point)
1312                                                                 # except we do it before the branch is made
1313                                                                 
1314                                                                 if brch.parent_pt:
1315                                                                         while len(pointlist) - start_pointlist > 2 and (Vector(pointlist[start_pointlist]) - brch.parent_pt.co).length < (brch.parent_pt.radius*2):
1316                                                                                 start_pointlist +=1
1317
1318                                                                 if is_first and brch.parent_pt:
1319                                                                         # We need to move the base point to a place where it looks good on the parent branch
1320                                                                         # to do this. move the first point, then remove the following points that look horrible (double back on themself)
1321                                                                         
1322                                                                         no = Vector(pointlist[0]) - Vector(pointlist[-1])
1323                                                                         no.length = brch.parent_pt.radius*2
1324                                                                         pointlist[0] = list(Vector(pointlist[0]) - no)
1325                                                                         
1326                                                                         """
1327                                                                         pointlist[1][0] = (pointlist[0][0] + pointlist[2][0])/2.0
1328                                                                         pointlist[1][1] = (pointlist[0][1] + pointlist[2][1])/2.0
1329                                                                         pointlist[1][2] = (pointlist[0][2] + pointlist[2][2])/2.0
1330                                                                         
1331                                                                         pointlist[2][0] = (pointlist[1][0] + pointlist[3][0])/2.0
1332                                                                         pointlist[2][1] = (pointlist[1][1] + pointlist[3][1])/2.0
1333                                                                         pointlist[2][2] = (pointlist[1][2] + pointlist[3][2])/2.0
1334                                                                         """
1335                                                                         
1336                                                                         
1337                                                                 # Done setting the start point
1338                                                                         
1339                                                                         
1340                                                                 len_pointlist = len(pointlist)
1341                                                                 if seg.children:
1342                                                                         len_pointlist -= 1
1343                                                                 
1344                                                                 # dont apply self_tree.limbScale here! - its alredy done
1345                                                                 bpoints = [ bpoint(brch, Vector(pointlist[ii]), Vector(), radlist[ii]) for ii in xrange(start_pointlist, len_pointlist) ]
1346                                                                 brch.bpoints.extend( bpoints )
1347                                                                 # ==============================================
1348                                                                 
1349                                                                 seg.new_bpt = bpoints[0]
1350                                                                 
1351                                                                 if seg.children:
1352                                                                         seg = seg.children[0]
1353                                                                 else:
1354                                                                         seg = None
1355                                                                 
1356                                                                 is_first = False
1357                                                                 
1358                                                         # done adding points
1359                                                         brch.calcData()
1360                                                         
1361                                                         
1362                                                         
1363                 
1364         def buildTwigs(self, twig_ratio, twig_select_mode, twig_select_factor):
1365                 
1366                 ratio_int = int(len(self.branches_all) * twig_ratio)
1367                 if ratio_int == 0:
1368                         return
1369                 
1370                 # So we only mix branches of similar lengths
1371                 branches_sorted = self.branches_all[:]
1372                 
1373                 # Get the branches based on our selection method!
1374                 if twig_select_mode==0:
1375                         branches_sorted.sort( key = lambda brch: brch.getLength())
1376                 elif twig_select_mode==1:
1377                         branches_sorted.sort( key = lambda brch:-brch.getLength())
1378                 elif twig_select_mode==2:
1379                         branches_sorted.sort( key = lambda brch:brch.getStraightness())
1380                 elif twig_select_mode==3:
1381                         branches_sorted.sort( key = lambda brch:-brch.getStraightness())
1382                 
1383                 factor_int = int(len(self.branches_all) * twig_select_factor)
1384                 branches_sorted[factor_int:] = []  # remove the last part of the list
1385                 
1386                 branches_sorted.sort( key = lambda brch: len(brch.bpoints))
1387                 
1388                 branches_new = []
1389                 #for i in xrange(ratio_int):
1390                 tot_twigs = 0
1391                 
1392                 step = 1
1393                 while tot_twigs < ratio_int and step < len(branches_sorted):
1394                         # Make branches from the existing
1395                         for j in xrange(step, len(branches_sorted)):
1396                                 brch = branches_sorted[j-step].mixToNew(branches_sorted[j], None)
1397                                 branches_new.append( brch )
1398                                 tot_twigs +=1
1399                                 
1400                                 if tot_twigs > ratio_int:
1401                                         break
1402                 
1403                 ### print "TwigCount", len(branches_new), ratio_int
1404                 
1405                 self.branches_twigs = branches_new
1406         
1407         def toDebugDisplay(self):
1408                 '''
1409                 Should be able to call this at any time to see whats going on, dosnt work so nice ATM.
1410                 '''
1411                 sce = bpy.data.scenes.active
1412                 
1413                 for ob in self.debug_objects:
1414                         for ob in sce.objects:
1415                                 sce.objects.unlink(ob)
1416                 
1417                 for branch_index, brch in enumerate(self.branches_all):
1418                         pt_index = 0
1419                         for pt_index, pt in enumerate(brch.bpoints):
1420                                 name = '%.3d_%.3d' % (branch_index, pt_index) 
1421                                 if pt.next==None:
1422                                         name += '_end'
1423                                 if pt.prev==None:
1424                                         name += '_start'
1425                                         
1426                                 ob = sce.objects.new('Empty', name)
1427                                 self.debug_objects.append(ob)
1428                                 mat = ScaleMatrix(pt.radius, 4) * TranslationMatrix(pt.co)
1429                                 ob.setMatrix(mat)
1430                                 ob.setDrawMode(8) # drawname
1431                 Blender.Window.RedrawAll()
1432                 
1433                 
1434         
1435         def toMesh(self, mesh=None,\
1436                         do_uv=True,\
1437                         do_uv_keep_vproportion=True,\
1438                         do_uv_vnormalize=False,\
1439                         do_uv_uscale=False,\
1440                         uv_image = None,\
1441                         uv_x_scale=1.0,\
1442                         uv_y_scale=4.0,\
1443                         do_uv_blend_layer= False,\
1444                         do_cap_ends=False,\
1445                 ):
1446                 
1447                 self.mesh = freshMesh(mesh)
1448                 totverts = 0
1449                 
1450                 for brch in self.branches_all:
1451                         totverts += len(brch.bpoints)
1452                 
1453                 self.mesh.verts.extend( [ (0.0,0.0,0.0) ] * ((totverts * 4)+1) ) # +1 is a dummy vert
1454                 verts = self.mesh.verts
1455                 
1456                 # Assign verts to points, 4 verts for each point.
1457                 i = 1 # dummy vert, should be 0
1458                 for brch in self.branches_all:                  
1459                         for pt in brch.bpoints:
1460                                 pt.verts[0] = verts[i]
1461                                 pt.verts[1] = verts[i+1]
1462                                 pt.verts[2] = verts[i+2]
1463                                 pt.verts[3] = verts[i+3]
1464                                 i+=4
1465                                 
1466                         # Do this again because of collapsing
1467                         # pt.calcVerts(brch)
1468                 
1469                 # roll the tube so quads best meet up to their branches.
1470                 for brch in self.branches_all:
1471                         #for pt in brch.bpoints:
1472                         if brch.parent_pt:
1473                                 
1474                                 # Use temp lists for gathering an average
1475                                 if brch.parent_pt.roll_angle == None:
1476                                         brch.parent_pt.roll_angle = [brch.getParentQuadAngle()]
1477                                 # More then 2 branches use this point, add to the list
1478                                 else:
1479                                         brch.parent_pt.roll_angle.append( brch.getParentQuadAngle() )
1480                 
1481                 # average the temp lists into floats
1482                 for brch in self.branches_all:
1483                         #for pt in brch.bpoints:
1484                         if brch.parent_pt and type(brch.parent_pt.roll_angle) == list:
1485                                 # print brch.parent_pt.roll_angle
1486                                 f = 0.0
1487                                 for val in brch.parent_pt.roll_angle:
1488                                         f += val
1489                                 brch.parent_pt.roll_angle = f/len(brch.parent_pt.roll_angle)
1490                 
1491                 # set the roll of all the first segments that have parents,
1492                 # this is because their roll is set from their parent quad and we dont want them to roll away from that.
1493                 for brch in self.branches_all:
1494                         if brch.parent_pt:
1495                                 # if the first joint has a child then apply half the roll
1496                                 # theres no correct solition here, but this seems ok
1497                                 if brch.bpoints[0].roll_angle != None:
1498                                         #brch.bpoints[0].roll_angle *= 0.5
1499                                         #brch.bpoints[0].roll_angle = 0.0
1500                                         #brch.bpoints[1].roll_angle = 0.0
1501                                         brch.bpoints[0].roll_angle = 0.0
1502                                         pass
1503                                 else:
1504                                         # our roll was set from the branches parent and needs no changing
1505                                         # set it to zero so the following functions know to interpolate.
1506                                         brch.bpoints[0].roll_angle = 0.0
1507                                         #brch.bpoints[1].roll_angle = 0.0
1508                 
1509                 '''
1510                 Now interpolate the roll!
1511                 The method used here is a little odd.
1512                 
1513                 * first loop up the branch and set each points value to the "last defined" value and record the steps
1514                 since the last defined value
1515                 * Do the same again but backwards
1516                 
1517                 now for each undefined value we have 1 or 2 values, if its 1 its simple we just use that value 
1518                 ( no interpolation ), if there are 2 then we use the offsets from each end to work out the interpolation.
1519                 
1520                 one up, one back, and another to set the values, so 3 loops all up.
1521                 '''
1522                 #### print "scan up the branch..."
1523                 for brch in self.branches_all:
1524                         last_value = None
1525                         last_index = -1
1526                         for i in xrange(len(brch.bpoints)):
1527                                 pt = brch.bpoints[i]
1528                                 if type(pt.roll_angle) in (float, int):
1529                                         last_value = pt.roll_angle
1530                                         last_index = i
1531                                 else:
1532                                         if type(last_value) in (float, int):
1533                                                 # Assign a list, because there may be a connecting roll value from another joint
1534                                                 pt.roll_angle = [(last_value, i-last_index)]
1535                                 
1536                         #### print "scan down the branch..."
1537                         last_value = None
1538                         last_index = -1
1539                         for i in xrange(len(brch.bpoints)-1, -1, -1): # same as above but reverse
1540                                 pt = brch.bpoints[i]
1541                                 if type(pt.roll_angle) in (float, int):
1542                                         last_value = pt.roll_angle
1543                                         last_index = i
1544                                 else:
1545                                         if last_value != None:
1546                                                 if type(pt.roll_angle) == list:
1547                                                         pt.roll_angle.append((last_value, last_index-i))
1548                                                 else:
1549                                                         #pt.roll_angle = [(last_value, last_index-i)]
1550                                                         
1551                                                         # Dont bother assigning a list because we wont need to add to it later
1552                                                         pt.roll_angle = last_value 
1553                         
1554                         # print "looping ,...."
1555                         ### print "assigning/interpolating roll values"
1556                         for pt in brch.bpoints:
1557                                 
1558                                 # print "this roll IS", pt.roll_angle
1559                                 
1560                                 if pt.roll_angle == None:
1561                                         continue
1562                                 elif type(pt.roll_angle) in (float, int):
1563                                         pass
1564                                 elif len(pt.roll_angle) == 1:
1565                                         pt.roll_angle = pt.roll_angle[0][0]
1566                                 else:
1567                                         # interpolate
1568                                         tot = pt.roll_angle[0][1] + pt.roll_angle[1][1]
1569                                         pt.roll_angle = \
1570                                          (pt.roll_angle[0][0] * (tot - pt.roll_angle[0][1]) +\
1571                                           pt.roll_angle[1][0] * (tot - pt.roll_angle[1][1])) / tot
1572                                         
1573                                         #### print pt.roll_angle, 'interpolated roll'
1574                                         
1575                                 pt.roll(pt.roll_angle)
1576                                 
1577                 # Done with temp average list. now we know the best roll for each branch.
1578                 
1579                 # mesh the data
1580                 for brch in self.branches_all:
1581                         for pt in brch.bpoints:
1582                                 pt.toMesh(self.mesh)
1583                 
1584                 #faces_extend = [ face for brch in self.branches_all for pt in brch.bpoints for face in pt.faces if face ]
1585                 
1586                 
1587                 
1588                 faces_extend = []
1589                 for brch in self.branches_all:
1590                         if brch.parent_pt:
1591                                 faces_extend.extend(brch.faces)
1592                         for pt in brch.bpoints:
1593                                 for face in pt.faces:
1594                                         if face:
1595                                                 faces_extend.append(face)
1596                 
1597                 if do_cap_ends:
1598                         # TODO - UV map and image?
1599                         faces_extend.extend([ brch.bpoints[-1].verts for brch in self.branches_all ])
1600                 
1601                 faces = self.mesh.faces
1602
1603                 faces.extend(faces_extend, smooth=True)
1604                 
1605                 if do_uv:
1606                         # Assign the faces back
1607                         face_index = 0
1608                         for brch in self.branches_all:
1609                                 if brch.parent_pt:
1610                                         for i in (0,1,2,3):
1611                                                 face = brch.faces[i] = faces[face_index+i]
1612                                         face_index +=4
1613                                 
1614                                 for pt in brch.bpoints:
1615                                         for i in (0,1,2,3):
1616                                                 if pt.faces[i]:
1617                                                         pt.faces[i] = faces[face_index]
1618                                                         face_index +=1
1619                         
1620                         #if self.mesh.faces:
1621                         #       self.mesh.faceUV = True
1622                         mesh.addUVLayer( 'base' )
1623                         
1624                         # rename the uv layer
1625                         #mesh.renameUVLayer(mesh.getUVLayerNames()[0], 'base')
1626                         
1627                         for brch in self.branches_all:
1628                                 
1629                                 uv_x_scale_branch = 1.0
1630                                 if do_uv_uscale:
1631                                         uv_x_scale_branch = 0.0
1632                                         for pt in brch.bpoints:
1633                                                 uv_x_scale_branch += pt.radius
1634                                         
1635                                         uv_x_scale_branch = uv_x_scale_branch / len(brch.bpoints)
1636                                         # uv_x_scale_branch = brch.bpoints[0].radius
1637                                 
1638                                 if do_uv_vnormalize:
1639                                         uv_normalize = []
1640                                 
1641                                 def uvmap_faces(my_faces, y_val, y_size):
1642                                         '''
1643                                         Accept a branch or pt faces
1644                                         '''
1645                                         uv_ls = [None, None, None, None]
1646                                         for i in (0,1,2,3):
1647                                                 if my_faces[i]:
1648                                                         if uv_image:
1649                                                                 my_faces[i].image = uv_image
1650                                                         uvs = my_faces[i].uv
1651                                                 else:
1652                                                         # Use these for calculating blending values
1653                                                         uvs = [Vector(0,0), Vector(0,0), Vector(0,0), Vector(0,0)]
1654                                                 
1655                                                 uv_ls[i] = uvs
1656                                                 
1657                                                 x1 = i*0.25 * uv_x_scale * uv_x_scale_branch    
1658                                                 x2 = (i+1)*0.25 * uv_x_scale * uv_x_scale_branch
1659                                                 
1660                                                 uvs[3].x = x1;
1661                                                 uvs[3].y = y_val+y_size
1662                                                 
1663                                                 uvs[0].x = x1
1664                                                 uvs[0].y = y_val
1665                                                 
1666                                                 uvs[1].x = x2
1667                                                 uvs[1].y = y_val
1668                                                 
1669                                                 uvs[2].x = x2
1670                                                 uvs[2].y = y_val+y_size
1671                                                 
1672                                                 if do_uv_vnormalize:
1673                                                         uv_normalize.extend(uvs)
1674                                         
1675                                         return uv_ls
1676                                         
1677                                 # Done uvmap_faces
1678                                 
1679                                 y_val = 0.0
1680                                 
1681                                 if brch.parent_pt:
1682                                         y_size = (brch.getParentFaceCent() - brch.bpoints[0].co).length
1683                                         
1684                                         if do_uv_keep_vproportion:
1685                                                 y_size = y_size / ((brch.bpoints[0].radius + brch.parent_pt.radius)/2) * uv_y_scale
1686                                         
1687                                         brch.uv = uvmap_faces(brch.faces, 0.0, y_size)
1688                                         
1689                                         y_val += y_size
1690                                 
1691                                 for pt in brch.bpoints:
1692                                         if pt.next:
1693                                                 y_size = (pt.co-pt.next.co).length
1694                                                 # scale the uvs by the radius, avoids stritching.
1695                                                 if do_uv_keep_vproportion:
1696                                                         y_size = y_size / pt.radius * uv_y_scale
1697                                                 pt.uv = uvmap_faces(pt.faces, y_val, y_size)
1698                                                 y_val += y_size
1699                                 
1700                                 
1701                                 if do_uv_vnormalize and uv_normalize:
1702                                         # Use yscale here so you can choose to have half the normalized value say.
1703                                         vscale = (1/uv_normalize[-1].y) * uv_y_scale
1704                                         for uv in uv_normalize:
1705                                                 uv.y *= vscale
1706                         
1707                         
1708                         # Done with UV mapping the first layer! now map the blend layers
1709                         if do_uv_blend_layer:
1710                                 # Set up the blend UV layer - this is simply the blending for branch joints
1711                                 mesh.addUVLayer( 'blend' )
1712                                 mesh.activeUVLayer = 'blend'
1713                                 
1714                                 # Set all faces to be on full blend
1715                                 for f in mesh.faces:
1716                                         for uv in f.uv:
1717                                                 uv.y = uv.x = 0.0
1718                                 
1719                                 for brch in self.branches_all:
1720                                         if brch.parent_pt:
1721                                                 for f in brch.faces:
1722                                                         if f:
1723                                                                 uvs = f.uv
1724                                                                 uvs[0].x = uvs[1].x = uvs[2].x = uvs[3].x = 0.0 
1725                                                                 uvs[0].y = uvs[1].y = 1.0 # swap these? - same as inverting the blend
1726                                                                 uvs[2].y = uvs[3].y = 0.0
1727                                 
1728                                 # Set up the join UV layer, this overlays nice blended
1729                                 mesh.addUVLayer( 'join' )
1730                                 mesh.activeUVLayer = 'join'
1731                                 
1732                                 # Set all faces to be on full blend
1733                                 for f in mesh.faces:
1734                                         for uv in f.uv:
1735                                                 uv.y = uv.x = 0.0
1736                                 
1737                                 for brch in self.branches_all:
1738                                         if brch.parent_pt:
1739                                                 # The UV's that this branch would cover if it was a face, 
1740                                                 uvs_base = brch.parent_pt.uv[brch.getParentQuadIndex()]
1741                                                 
1742                                                 uvs_base_mid = Vector(0,0)
1743                                                 for uv in uvs_base:
1744                                                         uvs_base_mid += uv
1745                                                         
1746                                                 uvs_base_mid *= 0.25
1747                                                 
1748                                                 # TODO - Factor scale and distance in here 
1749                                                 ## uvs_base_small = [(uv+uvs_base_mid)*0.5 for uv in uvs_base]
1750                                                 uvs_base_small = [uvs_base_mid, uvs_base_mid, uvs_base_mid, uvs_base_mid]
1751                                                 
1752                                                 if brch.faces[0]:
1753                                                         f = brch.faces[0]
1754                                                         uvs = f.uv
1755                                                         uvs[0][:] = uvs_base[0]
1756                                                         uvs[1][:] = uvs_base[1]
1757                                                         
1758                                                         uvs[2][:] = uvs_base_small[1]
1759                                                         uvs[3][:] = uvs_base_small[0]
1760                                                 
1761                                                 if brch.faces[1]:
1762                                                         f = brch.faces[1]
1763                                                         uvs = f.uv
1764                                                         uvs[0][:] = uvs_base[1]
1765                                                         uvs[1][:] = uvs_base[2]
1766                                                         
1767                                                         uvs[2][:] = uvs_base_small[2]
1768                                                         uvs[3][:] = uvs_base_small[1]
1769                                                         
1770                                                 if brch.faces[2]:
1771                                                         f = brch.faces[2]
1772                                                         uvs = f.uv
1773                                                         uvs[0][:] = uvs_base[2]
1774                                                         uvs[1][:] = uvs_base[3]
1775                                                         
1776                                                         uvs[2][:] = uvs_base_small[3]
1777                                                         uvs[3][:] = uvs_base_small[2]
1778                                                         
1779                                                 if brch.faces[3]:
1780                                                         f = brch.faces[3]
1781                                                         uvs = f.uv
1782                                                         uvs[0][:] = uvs_base[3]
1783                                                         uvs[1][:] = uvs_base[0]
1784                                                         
1785                                                         uvs[2][:] = uvs_base_small[0]
1786                                                         uvs[3][:] = uvs_base_small[3]
1787                         
1788                         mesh.activeUVLayer = 'base'  # just so people dont get worried the texture is not there - dosnt effect rendering.
1789                 else:
1790                         # no UV's
1791                         pass
1792                 
1793                 if do_cap_ends:
1794                         # de-select end points for 
1795                         i = len(faces)-1
1796                         
1797                         cap_end_face_start = len(faces) - len(self.branches_all)
1798                         
1799                         j = 0
1800                         for i in xrange(cap_end_face_start, len(faces)):
1801                                 self.branches_all[j].face_cap = faces[i]
1802                                 faces[i].sel = 0
1803                                 
1804                                 # default UV's are ok for now :/
1805                                 if do_uv and uv_image:
1806                                         faces[i].image = uv_image
1807                                 
1808                                 j +=1
1809                         
1810                         # set edge crease for capped ends.
1811                         for ed in self.mesh.edges:
1812                                 if ed.v1.sel==False and ed.v2.sel==False:
1813                                         ed.crease = 255
1814                                         ed.sel = True # so its all selected still
1815                         
1816                 del faces_extend
1817                 
1818                 return self.mesh
1819         
1820         def toLeafMesh(self, mesh_leaf,\
1821                         leaf_branch_limit = 0.5,\
1822                         leaf_branch_limit_rand = 0.8,\
1823                         leaf_branch_limit_type_curve = False,\
1824                         leaf_branch_limit_type_grow = False,\
1825                         leaf_branch_limit_type_fill = False,\
1826                         leaf_size = 0.5,\
1827                         leaf_size_rand = 0.5,\
1828                         leaf_branch_density = 0.2,\
1829                         leaf_branch_pitch_angle = 0.0,\
1830                         leaf_branch_pitch_rand = 0.2,\
1831                         leaf_branch_roll_rand = 0.2,\
1832                         leaf_branch_angle = 75.0,\
1833                         leaf_rand_seed = 1.0,\
1834                         leaf_object=None,\
1835                 ):
1836                 
1837                 '''
1838                 return a mesh with leaves seperate from the tree
1839                 
1840                 Add to the existing mesh.
1841                 '''
1842                 
1843                 #radius = [(pt.radius for pt in self.branches_all for pt in brch.bpoints for pt in brch.bpoints]
1844                 mesh_leaf = freshMesh(mesh_leaf)
1845                 self.mesh_leaf = mesh_leaf
1846                 
1847                 # if not leaf_object: return # make the dupli anyway :/ - they can do it later or the script could complain
1848                 
1849                 if leaf_branch_limit == 1.0:
1850                         max_radius = 1000000.0
1851                 else:
1852                         # We wont place leaves on all branches so...
1853                         # first collect stats, we want to know the average radius and total segments
1854                         totpoints = 0
1855                         radius = 0.0
1856                         max_radius = 0.0
1857                         for brch in self.branches_all:
1858                                 for pt in brch.bpoints:
1859                                         radius += pt.radius
1860                                         if pt.radius > max_radius:
1861                                                 max_radius = pt.radius
1862                                 
1863                                 #totpoints += len(brch.bpoints)
1864                                 
1865                         radius_max = max_radius * leaf_branch_limit
1866                 
1867                 verts_extend = []
1868                 faces_extend = []
1869                 
1870                 co1 = Vector(0.0, -0.5, -0.5)
1871                 co2 = Vector(0.0, -0.5, 0.5)
1872                 co3 = Vector(0.0, 0.5, 0.5)
1873                 co4 = Vector(0.0, 0.5, -0.5)
1874                 
1875                 rnd_seed = [leaf_rand_seed] # could have seed as an input setting
1876                 
1877                 for brch in self.branches_all:
1878                         
1879                         # quick test, do we need leaves on this branch?
1880                         if leaf_branch_limit != 1.0 and brch.bpoints[-1].radius > radius_max:
1881                                 continue
1882                         
1883                         
1884                         for pt in brch.bpoints:
1885                                 
1886                                 # For each point we can add 2 leaves
1887                                 for odd_even in (0,1):
1888                                         
1889                                         
1890                                         if      (pt == brch.bpoints[-1] and odd_even==1) or \
1891                                                 (leaf_branch_density != 1.0 and leaf_branch_density < next_random_num(rnd_seed)):
1892                                                 pass
1893                                         else:
1894                                                 if leaf_branch_limit_rand:
1895                                                         # (-1 : +1) * leaf_branch_limit_rand
1896                                                         rnd = 1 + (((next_random_num(rnd_seed) - 0.5) * 2 ) * leaf_branch_limit_rand)
1897                                                 else:
1898                                                         rnd = 1.0
1899                                                 
1900                                                 if pt.childCount == 0 and (leaf_branch_limit == 1.0 or (pt.radius * rnd) < radius_max):
1901                                                         leaf_size_tmp = leaf_size * (1.0-(next_random_num(rnd_seed)*leaf_size_rand))
1902                                                         
1903                                                         # endpoints dont rotate
1904                                                         if pt.next != None:
1905                                                                 cross1 = CrossVecs(zup, pt.no) # use this to offset the leaf later
1906                                                                 cross2 = CrossVecs(cross1, pt.no)
1907                                                                 if odd_even ==0:
1908                                                                         mat_yaw = RotationMatrix(leaf_branch_angle, 3, 'r',  cross2)
1909                                                                 else:
1910                                                                         mat_yaw = RotationMatrix(-leaf_branch_angle, 3, 'r', cross2)
1911                                                                 
1912                                                                 leaf_no = (pt.no * mat_yaw)
1913                                                                 
1914                                                                 # Correct upwards pointing from changing the yaw 
1915                                                                 #my_up = zup * mat
1916                                                                 
1917                                                                 # correct leaf location for branch width
1918                                                                 cross1.length = pt.radius/2
1919                                                                 leaf_co = pt.co + cross1
1920                                                         else:
1921                                                                 # no correction needed, we are at the end of the branch
1922                                                                 leaf_no = pt.no
1923                                                                 leaf_co = pt.co
1924                                                         
1925                                                         mat = Matrix([leaf_size_tmp,0,0],[0,leaf_size_tmp,0],[0,0,leaf_size_tmp]) * leaf_no.toTrackQuat('x', 'z').toMatrix()
1926                                                         
1927                                                         # Randomize pitch and roll for the leaf
1928                                                         
1929                                                         # work out the axis to pitch and roll
1930                                                         cross1 = CrossVecs(zup, leaf_no) # use this to offset the leaf later
1931                                                         if leaf_branch_pitch_rand or leaf_branch_pitch_angle:
1932                                                                 
1933                                                                 angle = -leaf_branch_pitch_angle
1934                                                                 if leaf_branch_pitch_rand:
1935                                                                         angle += leaf_branch_pitch_rand * ((next_random_num(rnd_seed)-0.5)*360)
1936                                                                 
1937                                                                 mat_pitch = RotationMatrix( angle, 3, 'r', cross1)
1938                                                                 mat = mat * mat_pitch
1939                                                         if leaf_branch_roll_rand:
1940                                                                 mat_roll =  RotationMatrix( leaf_branch_roll_rand * ((next_random_num(rnd_seed)-0.5)*360), 3, 'r', leaf_no)
1941                                                                 mat = mat * mat_roll
1942                                                         
1943                                                         mat = mat.resize4x4() * TranslationMatrix(leaf_co)
1944                                                         
1945                                                         i = len(verts_extend)
1946                                                         faces_extend.append( (i,i+1,i+2,i+3) )
1947                                                         verts_extend.extend([tuple(co4*mat), tuple(co3*mat), tuple(co2*mat), tuple(co1*mat)])
1948                                         #count += 1
1949                                 
1950                 
1951                 # setup dupli's
1952                 
1953                 self.mesh_leaf.verts.extend(verts_extend)
1954                 self.mesh_leaf.faces.extend(faces_extend)
1955                 
1956                 return self.mesh_leaf
1957         
1958         
1959         def toArmature(self, ob_arm, armature):
1960                 
1961                 armature.drawType = Blender.Armature.STICK
1962                 armature.makeEditable() # enter editmode
1963                 
1964                 # Assume toMesh has run
1965                 self.armature = armature
1966                 for bonename in armature.bones.keys():
1967                         del armature.bones[bonename]
1968                 
1969                 
1970                 group_names = []
1971                 
1972                 for i, brch in enumerate(self.branches_all):
1973                         
1974                         # get a list of parent points to make into bones. use parents and endpoints
1975                         bpoints_parent = [pt for pt in brch.bpoints if pt.childCount or pt.prev == None or pt.next == None]
1976                         bpbone_last = None
1977                         for j in xrange(len(bpoints_parent)-1):
1978                                 
1979                                 # bone container class
1980                                 bpoints_parent[j].bpbone = bpbone = bpoint_bone()
1981                                 bpbone.name = '%i_%i' % (i,j) # must be unique
1982                                 group_names.append(bpbone.name)
1983                                 
1984                                 bpbone.editbone = Blender.Armature.Editbone() # automatically added to the armature
1985                                 self.armature.bones[bpbone.name] = bpbone.editbone
1986                                 
1987                                 bpbone.editbone.head = bpoints_parent[j].co
1988                                 bpbone.editbone.head = bpoints_parent[j].co
1989                                 bpbone.editbone.tail = bpoints_parent[j+1].co
1990                                 
1991                                 # parent the chain.
1992                                 if bpbone_last:
1993                                         bpbone.editbone.parent = bpbone_last.editbone
1994                                         bpbone.editbone.options = [Blender.Armature.CONNECTED]
1995                                 
1996                                 bpbone_last = bpbone
1997                 
1998                 for brch in self.branches_all:
1999                         if brch.parent_pt: # We must have a parent
2000                                 
2001                                 # find the bone in the parent chain to use for the parent of this
2002                                 parent_pt = brch.parent_pt
2003                                 bpbone_parent = None
2004                                 while parent_pt:
2005                                         bpbone_parent = parent_pt.bpbone
2006                                         if bpbone_parent:
2007                                                 break
2008                                         
2009                                         parent_pt = parent_pt.prev
2010                                 
2011                                 
2012                                 if bpbone_parent:
2013                                         brch.bpoints[0].bpbone.editbone.parent = bpbone_parent.editbone
2014                                 else: # in rare cases this may not work. should be verry rare but check anyway.
2015                                         print 'this is really odd... look into the bug.'
2016                 
2017                 self.armature.update() # exit editmode
2018                 
2019                 # Skin the mesh
2020                 if self.mesh:
2021                         for group in group_names:
2022                                 self.mesh.addVertGroup(group)
2023                 
2024                 for brch in self.branches_all:
2025                         vertList = []
2026                         group = '' # dummy
2027                         
2028                         for pt in brch.bpoints:
2029                                 if pt.bpbone:
2030                                         if vertList:
2031                                                 self.mesh.assignVertsToGroup(group, vertList, 1.0, Blender.Mesh.AssignModes.ADD)
2032                                         
2033                                         vertList = []
2034                                         group = pt.bpbone.name
2035                                 
2036                                 vertList.extend( [v.index for v in pt.verts] )
2037                         
2038                         if vertList:
2039                                 self.mesh.assignVertsToGroup(group, vertList, 1.0, Blender.Mesh.AssignModes.ADD)
2040                 
2041                 return self.armature
2042         
2043         def toAction(self, ob_arm, texture, anim_speed=1.0, anim_magnitude=1.0, anim_speed_size_scale=True, anim_offset_scale=1.0):
2044                 # Assume armature
2045                 action = ob_arm.action
2046                 if not action:
2047                         action = bpy.data.actions.new()
2048                         action.fakeUser = False # so we dont get masses of bad data
2049                         ob_arm.action = action
2050                 
2051                 # Blender.Armature.NLA.ob_arm.
2052                 pose = ob_arm.getPose()
2053                 
2054                 for pose_bone in pose.bones.values():
2055                         pose_bone.insertKey(ob_arm, 0, [Blender.Object.Pose.ROT], True)
2056                 
2057                 # Now get all the IPO's
2058                 
2059                 ipo_dict = action.getAllChannelIpos()
2060                 # print ipo_dict
2061                 
2062                 # Sicne its per frame, it increases very fast. scale it down a bit
2063                 anim_speed = anim_speed/100
2064                 
2065                 # When we have the same trees next to eachother, they will animate the same way unless we give each its own texture or offset settings.
2066                 # We can use the object's location as a factor - this also will have the advantage? of seeing the animation move across the tree's
2067                 # allow a scale so the difference between tree textures can be adjusted.
2068                 anim_offset = self.objectCurve.matrixWorld.translationPart() * anim_offset_scale
2069                 
2070                 anim_speed_final = anim_speed
2071                 # Assign drivers to them all
2072                 for name, ipo in ipo_dict.iteritems():
2073                         tex_str = 'b.Texture.Get("%s")' % texture.name
2074                         
2075                         if anim_speed_size_scale:
2076                                 # Adjust the speed by the bone size.
2077                                 # get the point from the name. a bit ugly but works fine ;) - Just dont mess the index up!
2078                                 lookup = [int(val) for val in name.split('_')]
2079                                 pt = self.branches_all[ lookup[0] ].bpoints[ lookup[1] ]
2080                                 anim_speed_final = anim_speed / (1+pt.radius)
2081                         
2082                         cu = ipo[Blender.Ipo.PO_QUATX]
2083                         try:    cu.delBezier(0) 
2084                         except: pass
2085                         cu.driver = 2 # Python expression
2086                         cu.driverExpression = '%.3f*(%s.evaluate(((b.Get("curframe")*%.3f)+%.3f,%.3f,%.3f)).w-0.5)' % (anim_magnitude, tex_str, anim_speed_final, anim_offset.x, anim_offset.y, anim_offset.z)
2087                         
2088                         cu = ipo[Blender.Ipo.PO_QUATY]
2089                         try:    cu.delBezier(0) 
2090                         except: pass
2091                         cu.driver = 2 # Python expression
2092                         cu.driverExpression = '%.3f*(%s.evaluate((%.3f,(b.Get("curframe")*%.3f)+%.3f,%.3f)).w-0.5)' % (anim_magnitude, tex_str,  anim_offset.x, anim_speed_final, anim_offset.y, anim_offset.z)
2093                         
2094                         cu = ipo[Blender.Ipo.PO_QUATZ]
2095                         try:    cu.delBezier(0) 
2096                         except: pass
2097                         cu.driver = 2 # Python expression
2098                         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)
2099                 
2100 xyzup = Vector(1,1,1).normalize()
2101 xup = Vector(1,0,0)
2102 yup = Vector(0,1,0)
2103 zup = Vector(0,0,1)
2104
2105 class bpoint_bone:
2106         def __init__(self):
2107                 self.name = None
2108                 self.editbone = None
2109                 self.blenbone = None
2110                 self.posebone = None
2111
2112 class bpoint(object):
2113         ''' The point in the middle of the branch, not the mesh points
2114         '''
2115         __slots__ = 'branch', 'co', 'no', 'radius', 'vecs', 'verts', 'children', 'faces', 'uv', 'next', 'prev', 'childCount', 'bpbone', 'roll_angle', 'nextMidCo', 'childrenMidCo', 'childrenMidRadius', 'targetCos', 'inTwigBounds'
2116         def __init__(self, brch, co, no, radius):
2117                 self.branch = brch
2118                 self.co = co
2119                 self.no = no
2120                 self.radius = radius
2121                 self.vecs =             [None, None, None, None] # 4 for now
2122                 self.verts =    [None, None, None, None]
2123                 self.children = [None, None, None, None] # child branches, dont fill in faces here
2124                 self.faces = [None, None, None, None]
2125                 self.uv = None # matching faces, except - UV's are calculated even if there is no face, this is so we can calculate the blending UV's
2126                 self.next = None
2127                 self.prev = None
2128                 self.childCount = 0
2129                 self.bpbone = None # bpoint_bone instance
2130                 
2131                 # when set, This is the angle we need to roll to best face our branches
2132                 # the roll that is set may be interpolated if we are between 2 branches that need to roll.
2133                 # Set to None means that the roll will be left default (from parent)
2134                 self.roll_angle = None
2135                 
2136                 
2137                 # The location between this and the next point,
2138                 # if we want to be tricky we can try make this not just a simple
2139                 # inbetween and use the normals to have some curvature
2140                 self.nextMidCo = None
2141                 
2142                 # Similar to above, median point of all children
2143                 self.childrenMidCo = None
2144                 
2145                 # Similar as above, but for radius
2146                 self.childrenMidRadius = None
2147                 
2148                 # Target locations are used when you want to move the point to a new location but there are
2149                 # more then 1 influence, build up a list and then apply
2150                 self.targetCos = []
2151                 
2152                 # When we use twig bounding mesh, store if this point is in the bounding mesh. Assume true unless we set to false and do the test
2153                 self.inTwigBounds = True 
2154         
2155         def __repr__(self):
2156                 s = ''
2157                 s += '\t\tco:', self.co
2158                 s += '\t\tno:', self.no
2159                 s += '\t\tradius:', self.radius
2160                 s += '\t\tchildren:', [(child != False) for child in self.children]
2161                 return s
2162                 
2163         def makeLast(self):
2164                 self.next = None
2165                 self.nextMidCo = None
2166                 self.childrenMidCo = None
2167         
2168         def setCo(self, co):
2169                 self.co[:] = co
2170                 self.calcNextMidCo()
2171                 self.calcNormal()
2172                 
2173                 if self.prev:
2174                         self.prev.calcNextMidCo()
2175                         self.prev.calcNormal()
2176                         self.prev.calcChildrenMidData()
2177                 
2178                 if self.next:
2179                         self.prev.calcNormal()
2180                 
2181                 self.calcChildrenMidData()
2182                 
2183                 
2184         def nextLength(self):
2185                 return (self.co-self.next.co).length
2186         def prevLength(self):
2187                 return (self.co-self.prev.co).length
2188                 
2189         def hasOverlapError(self):
2190                 if self.prev == None:
2191                         return False
2192                 if self.next == None:
2193                         return False
2194                 '''
2195                 # see if this point sits on the line between its siblings.
2196                 co, fac = ClosestPointOnLine(self.co, self.prev.co, self.next.co)
2197                 
2198                 if fac >= 0.0 and fac <= 1.0:
2199                         return False # no overlap, we are good
2200                 else:
2201                         return True # error, some overlap
2202                 '''
2203                 
2204                 
2205                 # Alternate method, maybe better
2206                 ln = self.nextLength()
2207                 lp = self.prevLength()
2208                 ls = (self.prev.co-self.next.co).length
2209                 
2210                 # Are we overlapping? the length from our next or prev is longer then the next-TO-previous?
2211                 if ln>ls or lp>ls:
2212                         return True
2213                 else:
2214                         return False
2215                 
2216         
2217         def applyTargetLocation(self):
2218                 if not self.targetCos:
2219                         return False
2220                 elif len(self.targetCos) == 1:
2221                         co_all = self.targetCos[0]
2222                 else:
2223                         co_all = Vector()
2224                         for co in self.targetCos:
2225                                 co_all += co
2226                         co_all = co_all / len(self.targetCos)
2227                 
2228                 self.targetCos[:] = []
2229                 
2230                 length = (self.co-co_all).length
2231                 # work out if we are moving up or down
2232                 if AngleBetweenVecsSafe(self.no, self.co - co_all) < 90:
2233                         
2234                         # Up
2235                         while length > (self.co-self.prev.co).length:
2236                                 if not self.collapseUp():
2237                                         break
2238                         
2239                 else:
2240                         # Down
2241                         while length*2 > (self.co-self.next.co).length:
2242                                 if not self.collapseDown():
2243                                         break
2244                                 
2245                 self.setCo(co_all)
2246                 
2247                 return True
2248         
2249         def calcNextMidCo(self):
2250                 if not self.next:
2251                         return None
2252                 
2253                 # be tricky later.
2254                 self.nextMidCo = (self.co + self.next.co) * 0.5
2255         
2256         def calcNormal(self):
2257                 if self.prev == None:
2258                         self.no = (self.next.co - self.co).normalize()
2259                 elif self.next == None:
2260                         self.no = (self.co - self.prev.co).normalize()
2261                 else:
2262                         self.no = (self.next.co - self.prev.co).normalize()
2263         
2264         def calcChildrenMidData(self):
2265                 '''
2266                 Calculate childrenMidCo & childrenMidRadius
2267                 This is a bit tricky, we need to find a point between this and the next,
2268                 the medium of all children, this point will be on the line between this and the next.
2269                 '''
2270                 if not self.next:
2271                         return None
2272                 
2273                 # factor between this and the next point
2274                 radius = factor = factor_i = 0.0
2275                 
2276                 count = 0
2277                 for brch in self.children:
2278                         if brch: # we dont need the co at teh moment.
2279                                 co, fac = ClosestPointOnLine(brch.bpoints[0].co, self.co, self.next.co)
2280                                 factor_i += fac
2281                                 count += 1
2282                                 
2283                                 radius += brch.bpoints[0].radius
2284                 
2285                 if not count:
2286                         return
2287                 
2288                 # interpolate points 
2289                 factor_i        = factor_i/count
2290                 factor          = 1-factor_i
2291                 
2292                 self.childrenMidCo = (self.co * factor) + (self.next.co * factor_i)
2293                 self.childrenMidRadius = radius
2294                 
2295                 #debug_pt(self.childrenMidCo)
2296                 
2297         def getAbsVec(self, index):
2298                 # print self.vecs, index
2299                 return self.co + self.vecs[index]
2300         
2301         def slide(self, factor):
2302                 '''
2303                 Slides the segment up and down using the prev and next points
2304                 '''
2305                 self.setCo(self.slideCo(factor))
2306         
2307         def slideCo(self, factor):
2308                 if self.prev == None or self.next == None or factor==0.0:
2309                         return
2310                 
2311                 if factor < 0.0:
2312                         prev_co = self.prev.co
2313                         co = self.co
2314                         
2315                         ofs = co-prev_co
2316                         ofs.length = abs(factor)
2317                         self.co - ofs
2318                         
2319                         return self.co - ofs
2320                 else:
2321                         next_co = self.next.co
2322                         co = self.co
2323                         
2324                         ofs = co-next_co
2325                         ofs.length = abs(factor)
2326                         
2327                         return self.co - ofs
2328                 
2329         
2330         def collapseDown(self):
2331                 '''
2332                 Collapse the next point into this one
2333                 '''
2334                 
2335                 # self.next.next == None check is so we dont shorten the final length of branches.
2336                 if self.next == None or self.next.next == None or self.childCount or self.next.childCount:
2337                         return False
2338                 
2339                 self.branch.bpoints.remove(self.next)
2340                 self.next = self.next.next # skip 
2341                 self.next.prev = self
2342                 
2343                 # Watch this place - must update all data thats needed. roll is not calculaetd yet.
2344                 self.calcNextMidCo()
2345                 return True
2346                 
2347         def collapseUp(self):
2348                 '''
2349                 Collapse the previous point into this one
2350                 '''
2351                 
2352                 # self.next.next == None check is so we dont shorten the final length of branches.
2353                 if self.prev == None or self.prev.prev == None or self.prev.childCount or self.prev.prev.childCount:
2354                         return False
2355                 
2356                 self.branch.bpoints.remove(self.prev)
2357                 self.prev = self.prev.prev # skip 
2358                 self.prev.next = self
2359                 
2360                 # Watch this place - must update all data thats needed. roll is not calculaetd yet.
2361                 self.prev.calcNextMidCo()
2362                 return True
2363                 
2364         
2365         def smooth(self, factor, factor_joint):
2366                 '''
2367                 Blend this point into the other 2 points
2368                 '''
2369                 if self.next == None or self.prev == None: