0
$\begingroup$

I'm having an application where I want to remove and add points to a curve dynamically from within a frame-change handler. Before you think that this is not good practice and I should better use the start- and end-mapping feature of Blender: The actual application behind that is described here: Troubles with creating a track that is evolving frame by frame This is also including a description why start- and end-mapping is apparently not suitable for that application (as of the state of my understanding as of this writing...).

At first I wanted to care about the removal of a number of points at the end of the curve. I did run into an issue I was not able to solve yet. Here is my according handler that is being called with every frame-change:

def on_frame_changed2(Scene):
 current_frame = bpy.context.scene.frame_current

 # Force the EDIT-mode
 bpy.ops.object.mode_set(mode = 'EDIT')

 # Get a reference for the object that is containing the curve.
 trackpath_object = bpy.context.scene.objects.get('TrackPath2')

 # Determine the number of points we have in the curve
 current_point_count = trackpath_object.data.splines.active.point_count_u

 # If there are more points in the curve than the current frame number, delete
 # all points past the current frame number.
 if current_point_count-1 > current_frame:
     # Deselect everything so that we delete only those points we select later.
     bpy.ops.curve.select_all(action='DESELECT')
     # Select all points to be deleted.
     for i in range (current_frame+1, current_point_count):
         point = trackpath_object.data.splines.active.points[i]
         point.select = True
     # Delete all selected points
     bpy.ops.curve.delete(type='VERT')

The object "TrackPath2" is a path with poly-lines that has been created before.

Now the problem is that this is working fine as far as I did "some sort of selecting" the path manually beforehand. I write "some sort of selecting" because apparently this has nothing in common with the selection within the Blender GUI. When I'm in EDIT mode and choose "Select->All" for instance, there are selected all points of the path but not the path as such. Instead, I need to click on either a point of the path or on a link between two points. Then the path is "some sort of selected", I can change the frame, and the frame change handler deletes all desired points. As a result of the
bpy.ops.curve.delete(type='VERT') operation the path becomes "some sort of unselected" automatically and I need to click on it again to make the script working again.

When the path is not selected in the way it appears to be needed, the script is already failing at the evaluation of trackpath_object.data.splines.active.point_count_u Apparently, trackpath_object.data.splines.active is empty then resp. returns "None". I can check this also in the Python console. As soon as I click on the path it is not empty any more.

So the question is: How do I mimick this "click on the path" in the script so that it will be working under all circumstances?

$\endgroup$

1 Answer 1

0
$\begingroup$

The problem is that trackpath_object.data.splines.active is not set when the path is not "some sort of selected". Apparently a specific spline needs to be assigned here. In particular this would be

trackpath_object.data.splines.active = trackpath_object.data.splines[0]

However, it is not needed to use or assign the active spline at all. Instead, trackpath_object.data.splines[0] can be used directly.

For those who are interested, below I'm providing the full script that is also including adding new points to the curve (new points are taken from a small list of sample-coordinates). I'm not sure whether everything is made properly there, but all in all it appears to be working nicely. Please excuse that the code is some sort of ill-formatted here. I don't know how to fix this in the StackExchange system. But the important things should be visible...

Important note on animation rendering: The script below does still contain some problem during rendering the animation. I did not sort this out completely, but it is associated with forcing Blender into the edit mode. I did solve that by removing this forcing into the edit mode for rendering the animation but did switch into the edit mode manually before. Although this is not really nice, it is forking fine for me so far. If anybody knows what the issue is and how it can be fixed - your comments are welcome.

import bpy

coords_list = [[0,0,0], [1,0,0], [2,0,0], [3,0,0], [4,0,0], [5,1,0], [5,2,0], [5,3,0], [5,4,0]]

def on_frame_changed2(Scene):

current_frame = bpy.context.scene.frame_current
print("Frame number = ", current_frame)

# Get a reference for the object that is containing the curve.
trackpath_object = bpy.context.scene.objects.get('TrackPath2') 

# Set the active object (ToDo: Do we really need this?)
bpy.context.view_layer.objects.active = trackpath_object

# Force the EDIT-mode
bpy.ops.object.mode_set(mode = 'EDIT')

# Determine the number of points in the first spline
current_point_count = trackpath_object.data.splines[0].point_count_u

print("Current path point count = ", current_point_count)

if current_point_count-1 > current_frame:
    # We have to delete points.
    points_to_delete = current_point_count-1 - current_frame
    print(points_to_delete, " points have to be deleted...")
    # Deselect everything so that we delete only those points we select.
    bpy.ops.curve.select_all(action='DESELECT')
    # Select all points to be deleted.
    for i in range (current_frame+1, current_point_count):
        point = trackpath_object.data.splines[0].points[i]
        point.select = True
    # Delete the points
    bpy.ops.curve.delete(type='VERT')

elif current_point_count-1 < current_frame:
    # We have to insert points.
    # We limit the points have to be inserted to what we have available.
    if current_frame >= len(coords_list):
        print("Limiting points to be inserted")
        max_frame = len(coords_list) - 1
    else:
        max_frame = current_frame
     
    points_to_add = max_frame - current_point_count + 1
    print(points_to_add, " points have to be added...")
       
    trackpath_object.data.splines[0].points.add(points_to_add)
    # Walk through the new points and update their coordinates.
    for i in range(current_point_count,max_frame+1):
        trackpath_object.data.splines[0].points[i].co = coords_list[i] + [1.0]

bpy.app.handlers.frame_change_post.clear()

bpy.app.handlers.frame_change_pre.clear()

bpy.app.handlers.frame_change_post.append(on_frame_changed2)

$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .