# Python: Imported Curve points lose Z coordinate in Edit Mode

I'm trying to use bezier curves for editing paths of a custom game file format.

A weird bug (?) when switching to Edit Mode makes the bezier spline points lose their Z coordinate, it being set to 0, and I have no clue why.

Here's the code that simply creates a new bezier curve, adds a spline with enough points and feeds it the coordinates of the control points and handles.

# Create a bezier curve object representing the Path.
cu = bpy.data.curves.new("Path", 'CURVE')
ob = bpy.data.objects.new("Path", cu)
self.context.scene.objects.active = ob
# Add the points to a new spline.
sp = cu.splines.new('BEZIER')
sp.use_cyclic_u = path["IsClosed"]
points = path["PathPt"]
for i, point in enumerate(points):
pt = sp.bezier_points[i]
pt.co = vector_from_dict(point["Translate"], invert_z=True)
pt.handle_left = vector_from_dict(point["ControlPoints"][0], invert_z=True)
pt.handle_right = vector_from_dict(point["ControlPoints"][1], invert_z=True)
# Lock the transform as paths are always in the global coordinate system.
ob.lock_location = [True] * 3
ob.lock_rotation = [True] * 3
ob.lock_scale = [True] * 3
return ob

def vector_from_dict(dictionary, invert_z=False):
# Game file format is right handed with Y up, convert accordingly.
if invert_z:
return dictionary["X"], -dictionary["Z"], dictionary["Y"]
else:
return dictionary["X"], dictionary["Z"], dictionary["Y"]


As said, this imports fine and looks well at first. Hence this path of birds flying around the palm trees and above the house ceiling in the front:

But as soon as I enter Edit Mode, the path drops down to the floor, the Z coordinate of all points has become 0 (0 is far below the game model)!

It's indeed just Z losing its value, I imported the path again without editing it this time, making it very clear - the correct one is above, the one with the edit attempt lieing flat below:

Going back to Object Mode keeps these "corrupted" coordinates! What is going wrong here?

The file format itself is stored as binary, but also nothing special, and a Path in it can be represented as dictionaries and arrays like this:

{
"IsClosed": True,
"PathPoints":
[
{
"Handles":
[
{"X": -2374.132, "Y": 2985.336, "Z": 2211.747},
{"X": -2318.274, "Y": 2964.664, "Z": 1901.128}
],
# Can't import Rotate since no Blender support for bezier point normals =(
"Rotate": {"X": -2.684734, "Y": 0.167497, "Z": -3.044649},
"Translate": {"X": -2346.203, "Y": 2975, "Z": 2056.438}
},
{
"Handles":
[
{"X": -2277.908, "Y": 2960.383, "Z": 1596.964},
{"X": -2294.248, "Y": 2989.617, "Z": 1175.442}
],
"Rotate": {"X": -2.808016, "Y": -0.1063031, "Z": 3.136256},
"Translate": {"X": -2286.078, "Y": 2975, "Z": 1386.203}
},
# ... and so on for each point ...
]
}


Set your bezier curve to 3D either through the Properties Window > Object Data (Curve) > Shape > 3D or using the Pyhton API through bpy.types.Curve.dimensions setting it to 3D
• Just wow, how could I miss that? Interesting too see how it behaves when incorrectly set up from code. Setting it to 3D by code with cu.dimensions = '3D' fixes it =D