1
$\begingroup$

I have written a script that syncs the position of a bezier curve handle to an empty via a handler (bpy.app.handlers.scene_update_post):

def curve_handler(scene):

if bpy.data.objects.get('curve_name') is not None:
    curveOb = bpy.data.objects.get('curve_name')
    if bpy.data.objects.get('empty_name') is not None:
        e = bpy.data.objects.get('empty_name')
        curveOb.data.splines[0].bezier_points[1].handle_right = e.location

My problem is that the curve does not get updated. When I select the curve, go to edit mode and back, the handler jumps to the position of the empty. But not when I move the empty in object mode.

My current workaround is the following:

bpy.context.scene.objects.unlink(curveOb)
bpy.context.scene.objects.link(curveOb)

But that is apparently a super ugly hack. Is there a sane way to force redraw of a curve object in Blender?

$\endgroup$
2
$\begingroup$

What you are trying to do is already possible using a hook modifier. Manually you can go into edit mode, select a point and press ⎈ CtrlH->Hook to new object. This is also available to mesh objects which hooks the new object to the selected vertices.

We can create hooks using python. I'm not sure we can do this without the hook_assign operator, so we need to select the specific point and be in edit mode when we assign the point to the hook.

import bpy

obj = bpy.data.objects['BezierCurve']
# select and make it active (for later edit mode)
obj.select = True
bpy.context.scene.objects.active = obj

b_points = obj.data.splines[0].bezier_points
for p in b_points:
    p.select_control_point = False
    p.select_right_handle = False
    p.select_left_handle = False
b_points[0].select_right_handle = True

# create empty to hook to
hook_obj = bpy.data.objects.new('Hook', None)
bpy.context.scene.objects.link(hook_obj)
hook_obj.location = obj.matrix_world * b_points[0].handle_right

bpy.ops.object.mode_set(mode="EDIT")
hook_mod = obj.modifiers.new(name='Hook',type='HOOK')
hook_mod.object = hook_obj
bpy.ops.object.hook_assign()
bpy.ops.object.hook_reset() # needed if handle is not a 0,0,0
bpy.ops.object.mode_set(mode="OBJECT")
$\endgroup$
  • $\begingroup$ Actually I was trying to manipulate the handles, not the control points, so I modified your example code. I was not aware that hooks can be tied to handles as well, should have tried it before using an event handler. Thank you! $\endgroup$ – Gottfried Hofmann Mar 1 '17 at 17:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.