delay(info->router->get_departure_delay()),
duration(info->router->get_trip_duration()),
waypoint(0),
+ distance_traveled(0),
blocked_by(-1)
{
const Vehicle *veh = &info->train->get_vehicle(0);
iter = iter.next();
}
+ travel_multiplier = info->metrics[waypoint]->get_travel_multiplier(*track, track.reverse(path).entry());
+
update_estimate();
}
delay(other.delay),
duration(other.duration),
waypoint(other.waypoint),
+ travel_multiplier(other.travel_multiplier),
distance_traveled(other.distance_traveled),
remaining_estimate(other.remaining_estimate),
wait_time(other.wait_time),
Time::TimeDelta TrainRoutePlanner::TrainRoutingState::get_time_to_next_track() const
{
- return ((occupied_tracks->path_length-offset)/info->speed)*Time::sec+delay;
+ return ((occupied_tracks->path_length-offset)/info->speed)*Time::sec+delay+estimated_wait;
}
Time::TimeDelta TrainRoutePlanner::TrainRoutingState::get_time_to_pass(Track &trk) const
{
if(is_occupying(trk))
{
+ if(state==ARRIVED && info->has_duration)
+ return duration;
+
float passed_length = 0;
for(const OccupiedTrack *occ=occupied_tracks; (occ && occ->track!=&trk); occ=occ->next)
passed_length += occ->path_length;
occupied_tracks->n_tracks -= count_to_free;
}
- distance_traveled += distance;
- remaining_estimate -= distance;
+ distance_traveled += distance*travel_multiplier;
+ remaining_estimate -= distance*travel_multiplier;
}
void TrainRoutePlanner::TrainRoutingState::advance(const Time::TimeDelta &dt)
}
float secs = dt/Time::sec;
- // There may be negative delay remaining after previous step.
+ // There may be some delay remaining.
if(delay)
{
secs -= delay/Time::sec;
if(estimated_wait)
estimated_wait = max(estimated_wait-secs*Time::sec, Time::zero);
- if(state==MOVING)
+ float distance = info->speed*secs;
+ float remaining_on_track = occupied_tracks->path_length-offset;
+ if(state==MOVING || distance<remaining_on_track)
advance(info->speed*secs);
else if(state!=ARRIVED)
- wait_time += secs*Time::sec;
+ {
+ if(remaining_on_track>0)
+ {
+ advance(remaining_on_track);
+ wait_time += (secs-remaining_on_track/info->speed)*Time::sec;
+ }
+ else
+ wait_time += secs*Time::sec;
+ }
}
void TrainRoutePlanner::TrainRoutingState::advance_track(unsigned next_path)
{
float distance = occupied_tracks->path_length-offset;
+
track = track.next(path);
path = next_path;
occupied_tracks = new OccupiedTrack(*track, path, occupied_tracks);
+
advance(distance);
offset = 0;
+ travel_multiplier = info->metrics[waypoint]->get_travel_multiplier(*track, track.reverse(path).entry());
}
void TrainRoutePlanner::TrainRoutingState::set_path(unsigned p)
void TrainRoutePlanner::TrainRoutingState::update_estimate()
{
TrackIter iter = track.reverse(path);
- remaining_estimate = info->metrics[waypoint]->get_distance_from(*iter.track(), iter.entry());
+ const TrainRouteMetric *metric = info->metrics[waypoint];
+ remaining_estimate = metric->get_distance_from(*iter, iter.entry());
+ travel_multiplier = metric->get_travel_multiplier(*iter, iter.entry());
if(remaining_estimate>=0)
- remaining_estimate += occupied_tracks->path_length-offset;
+ remaining_estimate += (occupied_tracks->path_length-offset)*travel_multiplier;
}
bool TrainRoutePlanner::TrainRoutingState::is_viable() const
if(next.update_states() && next.check_deadlocks())
return;
- int train_index = find_next_train();
+ int train_index = next.find_next_train();
if(train_index<0)
return;
return;
}
- train.advance_track(0);
+ if(train.state==MOVING)
+ train.advance_track(0);
+ else
+ {
+ new_steps.push_back(next);
+ return;
+ }
const TrackType::Endpoint &entry_ep = train.track.endpoint();
if(train.critical)
int TrainRoutePlanner::RoutingStep::find_next_train() const
{
+ /* Pick a moving train with the lowest time to next track. A train that
+ just became blocked can still travel until the end of its current track,
+ so consider those too. */
Time::TimeDelta min_dt;
int next_train = -1;
for(unsigned i=0; i<trains.size(); ++i)
- if(trains[i].state==MOVING)
+ {
+ Time::TimeDelta dt;
+ if(trains[i].state==MOVING || (trains[i].state==BLOCKED && prev && prev->trains[i].state==MOVING))
+ dt = trains[i].get_time_to_next_track();
+ else if(trains[i].state==BLOCKED && trains[trains[i].blocked_by].state==ARRIVED)
+ dt = trains[i].estimated_wait;
+ else
+ continue;
+
+ if(dt<min_dt || next_train<0)
{
- Time::TimeDelta dt = trains[i].get_time_to_next_track();
- if(dt<min_dt || next_train<0)
- {
- min_dt = dt;
- next_train = i;
- }
+ min_dt = dt;
+ next_train = i;
}
+ }
return next_train;
}