Related: 111, 112, 155
gabriel has pointed out the following problem with the train collision algorithm:
Collisions are checked for in train_step_c, after the train has already moved into the colliding position. If the train, for instance, moves 10 nodes, and collides after 2 nodes, the train still moves the full 10 nodes forward and thus comes to halt 8 nodes after the obstruction.
To solve this, collisions must be checked for after calculating the new position, but before actually advancing the train. If a collision is detected, the target index must be clipped accordingly.
The implementation of this would be straightforward, but it would be good to overthink the way collisions between trains on the same track are handled. In short, if the active train and the colliding train are on the same track, the stopping index should be the exact index where the other train ends. For this, we need a advtrains.path_project(train, other_train) function which returns the indices and orientation of the other_train projected on train's path. With this, we can also handle matching the coupling ends of trains in order to solve 155.
A further step to be considered is to integrate the on-track collisions into the LZB subsystem, to allow for "drive on sight" or "moving block" systems. Details of this are to be thought of.