I've been trying to generalize the solution to this question: Using python to create a curve and attach its endpoints with hooks to two spheres, so that it can work on an arbitrarily long bezier curve, but I can't seem to get the
hook_assign() function to work right. (See also How to use bpy ops that take a modifier Enum as an argument?)
When I print the state of
.select_control_point for each point on the curve before (or after) I call the
hook_assign function, the console output looks right except the function still returns
Warning: Requires selected vertices or active vertex group.
Below the code is some sample console feedback.
noodcurv = bpy.data.curves.new('noodcurve', type='CURVE') #create a new curve noodcurv.dimensions = '3D' #set some settings noodcurv.resolution_u = 2 noodcurv.bevel_object = bevob noodcurv.use_fill_caps = True bez = noodcurv.splines.new('BEZIER') #create a new spline bez.bezier_points.add(len(coords)-1) #add points for k, coord in enumerate(coords): #set coordinates & handles p = bez.bezier_points[k] p.co = coord p.handle_right_type = 'VECTOR' #or 'AUTOMATIC', 'ALIGNED', 'FREE_ALIGN' p.handle_left_type = 'VECTOR' noodcurvobj = bpy.data.objects.new('noodcurve', noodcurv) #create object modnames = ['hook.'+str(k).zfill(3) for k in range(len(coords))] #create modifier names for k, coord in enumerate(coords): #create modifiers & set Parent Object noodcurvobj.modifiers.new(modnames[k], type='HOOK') noodcurvobj.modifiers[modnames[k]].object = bpy.context.scene.objects['link'+modnames[k][4:]] scn = bpy.context.scene #scene variable scn.objects.link(noodcurvobj) #link to scene & activate scn.objects.active = noodcurvobj bez.bezier_points.select_control_point = True #this fixes the warning!? bpy.ops.object.mode_set(mode='EDIT') #change context for k, coord in enumerate(coords): #assign points to modifiers p = bez.bezier_points[k] #assign points to variables p.select_control_point = True for q,t in enumerate(bez.bezier_points): #debugging check print('control point: ', q, ' is', t.select_control_point) bpy.ops.object.hook_assign(modifier=modnames[k]) #assign vextex to modifier p.select_control_point = False bpy.ops.object.mode_set(mode='OBJECT')
Some of the console output:
control point: 0 is True control point: 1 is False control point: 2 is False control point: 3 is False control point: 4 is False Warning: Requires selected vertices or active vertex group control point: 0 is False control point: 1 is True control point: 2 is False control point: 3 is False control point: 4 is False Warning: Requires selected vertices or active vertex group control point: 0 is False control point: 1 is False control point: 2 is True control point: 3 is False control point: 4 is False Warning: Requires selected vertices or active vertex group ...
(I know it'd be better if I could use one loop instead of three, but as I ran into problems I kept rearranging stuff to more closely mimic the original answer, and at this point I'm out of ideas!)
I also noticed that if I set
.select_control_point = True for one or more points before I enter the third loop, the warnings go away and the modifiers are all assigned to whatever control point(s) I selected before the loop (even though the console output will indicate I'm still stepping through the selected points correctly).
So what am I missing?
.mode_set()function into the loop, I get an error,
IndexError: bpy_prop_collection[index]: index 0 out of range, size 0, and if I move the
.select_control_points = Trueto below the
.mode_set()function I get the
Warning: Requires selected vertices or active vertex groupproblem again. And if I place
.mode_set()functions inside the loop (to
mode='EDIT'at the start and 'mode='OBJECT' at the end, I get some weird errors, usually
IndexError, but at other times an endless loop or segmentation fault, or very large (negative) index? $\endgroup$