return set_route(route);
}
-bool Train::divert(Track &from)
-{
- if(!from.get_turnout_id())
- throw invalid_argument("Train::divert");
- if(routes.empty())
- return false;
-
- unsigned path = 0;
- unsigned entry = 0;
- list<RouteRef>::iterator route = routes.begin();
-
- // Follow our routes to find out where we're entering the turnout
- for(TrackLoopIter track = blocks.front().track_iter();;)
- {
- if(!advance_route(route, *track))
- return false;
-
- if(&*track==&from)
- {
- Block &block = track->get_block();
- if(block.get_train()==this && !free_block(block))
- return false;
-
- int route_path = route->route->get_turnout(from.get_turnout_id());
-
- // Check that more than one path is available
- unsigned ep_paths = track.endpoint().paths;
- if(!(ep_paths&(ep_paths-1)))
- return false;
-
- // Choose some other path
- for(int i=0; ep_paths>>i; ++i)
- if((ep_paths&(1<<i)) && i!=route_path)
- {
- path = i;
- break;
- }
-
- entry = track.entry();
- break;
- }
-
- track = track.next(route->route->get_path(*track));
-
- if(!track || track.looped())
- return false;
- }
-
- TrackIter track = TrackIter(&from, entry).next(path);
- if(!track)
- return false;
-
- set<Track *> tracks;
- for(list<RouteRef>::iterator i=routes.begin(); i!=routes.end(); ++i)
- tracks.insert(i->route->get_tracks().begin(), i->route->get_tracks().end());
- RefPtr<Route> diversion = Route::find(track, tracks);
- if(!diversion)
- return false;
-
- diversion->set_name("Diversion");
- diversion->add_track(from);
- diversion->set_turnout(from.get_turnout_id(), path);
-
- if(!is_valid_diversion(*diversion, TrackIter(&from, entry)))
- return false;
-
- // Follow the diversion route until we get back to the original route
- list<RouteRef>::iterator end = routes.end();
- while(1)
- {
- for(list<RouteRef>::iterator i=route; (end==routes.end() && i!=routes.end()); ++i)
- if(i->route->has_track(*track))
- end = i;
-
- if(end!=routes.end())
- break;
- else if(!diversion->has_track(*track))
- throw logic_error("bad diversion");
-
- track = track.next(diversion->get_path(*track));
- }
-
- if(route==end)
- // We are rejoining the same route we diverted from, duplicate it
- routes.insert(end, *route);
- else
- {
- ++route;
- routes.erase(route, end);
- }
- routes.insert(end, RouteRef(diversion.release(), from.get_turnout_id()));
-
- return true;
-}
-
const Route *Train::get_route() const
{
if(routes.empty())
return 0;
- return routes.front().route;
+ return routes.front();
}
void Train::place(Block &block, unsigned entry)
if(!routes.empty())
{
- list<RouteRef>::const_iterator i = routes.begin();
- for(; (i!=routes.end() && i->route->is_temporary()); ++i) ;
+ list<const Route *>::const_iterator i = routes.begin();
+ for(; (i!=routes.end() && (*i)->is_temporary()); ++i) ;
if(i!=routes.end())
- st.push_back((DataFile::Statement("route"), i->route->get_name()));
+ st.push_back((DataFile::Statement("route"), (*i)->get_name()));
}
// XXX Need more generic way of saving AI state
// Check if we've reached the next route
if(routes.size()>1)
{
- const Route &route = *(++routes.begin())->route;
+ const Route &route = **(++routes.begin());
for(BlockList::iterator j=cur_blocks_end; j!=end; ++j)
if(route.has_track(*j->track_iter()))
{
routes.pop_front();
// XXX Exceptions?
- signal_route_changed.emit(routes.front().route);
+ signal_route_changed.emit(routes.front());
break;
}
}
dist += (*i)->get_path_length(i->entry());
}
- list<RouteRef>::iterator cur_route = routes.begin();
+ list<const Route *>::iterator cur_route = routes.begin();
advance_route(cur_route, *start.track_iter());
float approach_margin = 50*layout.get_catalogue().get_scale();
BlockIter block = start;
list<BlockIter>::iterator good_end = blocks.end();
- Track *divert_track = 0;
- bool try_divert = false;
Train *blocking_train = 0;
BlockList contested_blocks;
while(1)
{
BlockIter last = block;
- block = block.next(cur_route!=routes.end() ? cur_route->route : 0);
+ block = block.next(cur_route!=routes.end() ? *cur_route : 0);
if(!block || block->get_endpoints().size()<2)
{
if(!blocking_train)
{
yield_to(*blocking_train);
pending_block = contested_blocks.front().block();
- try_divert = divert_track;
break;
}
}
contested_blocks.push_back(block);
continue;
}
- else if(divert_track && (entry_conflict || exit_conflict || !other_train->is_active()))
- // We are blocked, but there's a diversion possibility
- try_divert = true;
if(!reserved)
{
}
}
- if(block->get_turnout_id())
- {
- const TrackType::Endpoint &track_ep = track.endpoint();
- bool multiple_paths = (track_ep.paths&(track_ep.paths-1));
-
- if(multiple_paths && cur_route!=routes.end() && cur_route->diversion!=block->get_turnout_id())
- /* There's multiple paths to be taken and we are on a route - take
- note of the diversion possibility */
- divert_track = &*track;
- }
-
if(!contested_blocks.empty() && contested_blocks.front()==block)
contested_blocks.pop_front();
// Make any sensorless blocks at the beginning immediately current
while(cur_blocks_end!=clear_blocks_end && !(*cur_blocks_end)->get_sensor_id())
++cur_blocks_end;
-
- if(try_divert && divert(*divert_track))
- reserve_more();
}
void Train::check_turnout_paths(bool set)
*i = i->reverse();
}
-bool Train::advance_route(list<RouteRef>::iterator &iter, Track &track)
+bool Train::advance_route(list<const Route *>::iterator &iter, Track &track)
{
- while(iter!=routes.end() && !iter->route->has_track(track))
+ while(iter!=routes.end() && !(*iter)->has_track(track))
++iter;
if(iter==routes.end())
return false;
- list<RouteRef>::iterator next = iter;
- ++next;
- if(next!=routes.end() && next->diversion && next->route->has_track(track))
- iter = next;
-
return true;
}
return lead;
}
-bool Train::is_valid_diversion(const Route &diversion, const TrackIter &from)
-{
- float diversion_len = 0;
- TrackLoopIter track1 = from;
- while(diversion.has_track(*track1))
- {
- unsigned path = diversion.get_path(*track1);
- diversion_len += track1->get_type().get_path_length(path);
-
- track1 = track1.next(path);
-
- if(!track1 || track1.looped())
- return false;
- }
-
- list<RouteRef>::iterator route = routes.begin();
- if(!advance_route(route, *from))
- return false;
-
- float route_len = 0;
- TrackLoopIter track2 = from;
- while(1)
- {
- unsigned path = route->route->get_path(*track2);
- route_len += track2->get_type().get_path_length(path);
-
- bool ok = (track2!=from && diversion.has_track(*track2));
-
- track2 = track2.next(path);
- if(!track2)
- return false;
-
- if(ok)
- break;
-
- if(track2.looped())
- return false;
-
- if(!advance_route(route, *track2))
- return false;
- }
-
- // Must end up at the same place through both routes
- if(track2!=track1)
- return false;
-
- return diversion_len<route_len*1.2;
-}
-
-
-Train::RouteRef::RouteRef(const Route *r, unsigned d):
- route(r),
- diversion(d)
-{ }
-
Train::Loader::Loader(Train &t):
DataFile::ObjectLoader<Train>(t),