From 9815c9f587063b3378e07bcd868c0ff6055a4e15 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Tue, 15 Apr 2014 18:25:34 +0300 Subject: [PATCH] Keep better track of routes Finding the correct route for each allocated block from scratch is prone to errors if the combined route contains loops. --- source/libr2c2/trainrouter.cpp | 111 ++++++++++++++++++++++----------- source/libr2c2/trainrouter.h | 5 +- 2 files changed, 76 insertions(+), 40 deletions(-) diff --git a/source/libr2c2/trainrouter.cpp b/source/libr2c2/trainrouter.cpp index 4b7e1bc..44a97f5 100644 --- a/source/libr2c2/trainrouter.cpp +++ b/source/libr2c2/trainrouter.cpp @@ -84,10 +84,30 @@ const Route *TrainRouter::get_route() const void TrainRouter::route_changed() { - train.stop_at(0); - arriving = 0; 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); @@ -238,6 +258,9 @@ void TrainRouter::save(list &st) const void TrainRouter::block_reserved(Block &block, Train *t) { + if(routes.empty()) + return; + if(t!=&train) { if(!t) @@ -265,35 +288,46 @@ void TrainRouter::block_reserved(Block &block, Train *t) } } - 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; } + 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); } } @@ -406,26 +440,27 @@ Route *TrainRouter::create_lead_route(Route *lead, const Route *target) return lead; } -bool TrainRouter::advance_route(RouteList::iterator &iter, const Block &block) +bool TrainRouter::is_valid_for_track(const Route &route, Track &track) const { - const set &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::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) diff --git a/source/libr2c2/trainrouter.h b/source/libr2c2/trainrouter.h index 47a409c..1c523d8 100644 --- a/source/libr2c2/trainrouter.h +++ b/source/libr2c2/trainrouter.h @@ -46,6 +46,7 @@ private: int priority; RouteList routes; + RouteList::iterator reserving_route; unsigned arriving; const TrackChain *destination; std::vector waypoints; @@ -94,8 +95,8 @@ private: 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 &); }; -- 2.43.0