ChildOf constraint redraw problem

I am attempting to add a ChildOf constraint to an object with “use_location_x” = False. After setting up the constraint the constrained object translates to a position on top of the target object, an undesirable effect. When I do everything via the user interface I see that I have to click the “Set Inverse” button to make the object return to its original position. However, when I do everything from a script (using the Alt-P method in the text editor) the object refuses to return to its original position. The inverse_matrix does indeed get properly set, but I see no effect in the 3D View. What am I missing?


import bpy

bpy.ops.mesh.primitive_cube_add()
c01 = bpy.context.active_object

bpy.ops.mesh.primitive_cube_add(location=(1.0,0,2.5))
c02 = bpy.context.active_object

CoC = c01.constraints.new("CHILD_OF")
CoC.name = 'Child_Of_c02'
CoC.target = c02
CoC.use_location_x = False

for x_obj in bpy.data.objects:
    x_obj.select = False
    
c01.select = True
bpy.context.scene.objects.active = c01

print()

print(c01.constraints['Child_Of_c02'].inverse_matrix,'
')

bpy.ops.constraint.childof_set_inverse(constraint="Child_Of_c02", owner='OBJECT')

# What must go here to make c01 display correctly in 3D View ?

print(c01.constraints['Child_Of_c02'].inverse_matrix,'
')

Stumbled upon this “solution”. If I toggle c01 in and out of edit mode the object is redrawn with the inverse_matrix applied.

import bpy

bpy.ops.mesh.primitive_cube_add()
c01 = bpy.context.active_object

bpy.ops.mesh.primitive_cube_add(location=(1.0,0,2.5))
c02 = bpy.context.active_object

CoC = c01.constraints.new("CHILD_OF")
CoC.name = 'Child_Of_c02'
CoC.target = c02
CoC.use_location_x = False

for x_obj in bpy.data.objects:
    x_obj.select = False
    
c01.select = True
bpy.context.scene.objects.active = c01

print()

print(c01.constraints['Child_Of_c02'].inverse_matrix,'
')

bpy.ops.constraint.childof_set_inverse(constraint="Child_Of_c02", owner='OBJECT')

# What must go here to make c01 display correctly in 3D View ?
# Answer: Toggle c01 in and out of edit mode.

bpy.ops.object.editmode_toggle()
bpy.ops.object.editmode_toggle()

print(c01.constraints['Child_Of_c02'].inverse_matrix,'
')

Not really an elegant solution.

Aha that gives it away.

You need to call the mesh.update() method.


mesh = c01.data
mesh.update()

Great! Thanks batFINGER!

Now I have another problem. I am trying to constrain an object between two others in a single dimension (x). Here is the code:

import bpy

bpy.ops.mesh.primitive_cube_add(location=(-4,0,0))
c01 = bpy.context.active_object

bpy.ops.mesh.primitive_cube_add(location=(4.0,0,0))
c02 = bpy.context.active_object

bpy.ops.object.add(type='EMPTY', location=(2.0,0,0))
e01 = bpy.context.active_object
#e01.hide = True

CoC = e01.constraints.new("CHILD_OF")
CoC.name = 'Child_Of_c02'
CoC.target = c02
bpy.ops.constraint.childof_set_inverse(constraint="Child_Of_c02", owner='OBJECT')

# What can I do here to force the updating of an Empty object?

bpy.ops.mesh.primitive_cube_add(location=(0,0,0))
c03 = bpy.context.active_object

c03.constraints.new('FLOOR')
fc = c03.constraints[0]
fc.target = c01
fc.name = "LeftFloor"
fc.floor_location = 'FLOOR_X'
fc.offset = 2.0

c03.constraints.new('FLOOR')
fc = c03.constraints[1]
fc.target = e01
fc.name = "RightFloor"
fc.floor_location = 'FLOOR_NEGATIVE_X'

Now I am applying the childof_set_inverse operation to an object of type ‘EMPTY’, which has no data to update. (Note that if the FLOOR constraint would allow me to specify a negative offset value I would not have to use the empty.)

Any ideas regarding another way to achieve the result I am going for would also be appreciated.