Finding the correct route for each allocated block from scratch is prone
to errors if the combined route contains loops.
void TrainRouter::route_changed()
{
void TrainRouter::route_changed()
{
- train.stop_at(0);
- arriving = 0;
BlockIter fncb = train.get_first_noncritical_block();
BlockIter fncb = train.get_first_noncritical_block();
- train.refresh_blocks_from(*fncb);
+
+ reserving_route = routes.begin();
+ bool already_at_end = false;
+ if(!routes.empty())
+ {
+ TrackIter track = train.get_block_allocator().first().track_iter();
+ for(; track; track=track.next())
+ {
+ if(!advance_to_track(reserving_route, *track))
+ {
+ already_at_end = true;
+ break;
+ }
+ if(&track->get_block()==fncb.block())
+ break;
+ }
+ }
+
+ if(!already_at_end)
+ {
+ train.stop_at(0);
+ train.refresh_blocks_from(*fncb);
+ }
const Route *route = get_route();
signal_route_changed.emit(route);
const Route *route = get_route();
signal_route_changed.emit(route);
void TrainRouter::block_reserved(Block &block, Train *t)
{
void TrainRouter::block_reserved(Block &block, Train *t)
{
+ if(routes.empty())
+ return;
+
- BlockIter b_iter = t->get_block_allocator().iter_for(block);
+ TrackIter track = train.get_block_allocator().iter_for(block).track_iter();
- RouteList::iterator route = routes.begin();
- if(advance_route(route, block))
+ // Is the block a turnout? If so, set it to the proper path.
+ if(unsigned taddr = block.get_turnout_address())
- // Check if the block is a turnout and set it to proper path
- if(unsigned taddr = block.get_turnout_address())
+ int path = (*reserving_route)->get_turnout(taddr);
+ if(path>=0)
+ track->set_active_path(path);
+ }
+
+ if(reserving_route==routes.end() || !(*reserving_route)->has_track(*track))
+ {
+ reserving_route = routes.begin();
+ track = t->get_block_allocator().first().track_iter();
+ for(; track; track=track.next())
- int path = (*route)->get_turnout(taddr);
- if(path>=0)
- b_iter.track_iter()->set_active_path(path);
+ if(!advance_to_track(reserving_route, *track))
+ throw logic_error("internal error (reservation outside of route)");
+ else if(&track->get_block()==&block)
+ break;
- // Check if the next block is still part of the designated route
- BlockIter b_iter_next = b_iter.next(*route);
-
- RouteList::iterator next_route = route;
- if(!advance_route(next_route, *b_iter_next))
+ // Do we need to move to the next route?
+ for(; track; track=track.next((*reserving_route)->get_path(*track)))
+ {
+ if(!advance_to_track(reserving_route, *track))
{
train.stop_at(&block);
return;
}
{
train.stop_at(&block);
return;
}
+ if(&track->get_block()!=&block)
+ break;
+ }
- if(!sequence_points.empty())
- {
- SequencePoint &sp = sequence_points.front();
- if(sp.block==b_iter_next.block() && !sp.is_cleared())
- train.stop_at(&block);
- }
+ if(!sequence_points.empty())
+ {
+ SequencePoint &sp = sequence_points.front();
+ if(sp.block==&track->get_block() && !sp.is_cleared())
+ train.stop_at(&block);
-bool TrainRouter::advance_route(RouteList::iterator &iter, const Block &block)
+bool TrainRouter::is_valid_for_track(const Route &route, Track &track) const
- const set<Track *> &tracks = block.get_tracks();
- unsigned turnout_addr = block.get_turnout_address();
- for(; iter!=routes.end(); ++iter)
- {
- if(turnout_addr && (*iter)->get_turnout(turnout_addr)<0)
- continue;
- for(set<Track *>::const_iterator j=tracks.begin(); j!=tracks.end(); ++j)
- if((*iter)->has_track(**j))
- return true;
- }
-
- return false;
+ if(!route.has_track(track))
+ return false;
+ if(track.get_type().is_turnout() && route.get_turnout(track.get_turnout_address())<0)
+ return false;
+ return true;
-bool TrainRouter::is_on_route(const Block &block)
+bool TrainRouter::advance_to_track(RouteList::iterator &route, Track &track)
- RouteList::iterator iter = routes.begin();
- return advance_route(iter, block);
+ if(!is_valid_for_track(**route, track))
+ {
+ ++route;
+ if(route==routes.end())
+ return false;
+ if(!is_valid_for_track(**route, track))
+ throw logic_error("internal error (routes are not continuous)");
+ }
+
+ return true;
}
void TrainRouter::start_planning(Layout &layout)
}
void TrainRouter::start_planning(Layout &layout)
int priority;
RouteList routes;
int priority;
RouteList routes;
+ RouteList::iterator reserving_route;
unsigned arriving;
const TrackChain *destination;
std::vector<const TrackChain *> waypoints;
unsigned arriving;
const TrackChain *destination;
std::vector<const TrackChain *> waypoints;
void create_metrics();
Route *create_lead_route(Route *, const Route *);
void create_metrics();
Route *create_lead_route(Route *, const Route *);
- bool advance_route(RouteList::iterator &, const Block &);
- bool is_on_route(const Block &);
+ bool is_valid_for_track(const Route &, Track &) const;
+ bool advance_to_track(RouteList::iterator &, Track &);
static void start_planning(Layout &);
};
static void start_planning(Layout &);
};