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)
set_active(false);
accurate_position = false;
+ blocks.push_back(BlockIter(&block, entry));
if(!block.reserve(this))
+ {
+ blocks.pop_back();
return;
+ }
- blocks.push_back(BlockIter(&block, entry));
if(reverse)
{
TrackIter track = BlockIter(&block, entry).reverse().track_iter();
if(dist>10*layout.get_catalogue().get_scale())
{
- blocks.front()->reserve(0);
+ Block &block = *blocks.front();
blocks.pop_front();
+ block.reserve(0);
}
}
}
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;
}
}
}
}
+ blocks.push_back(block);
bool reserved = block->reserve(this);
if(!reserved)
{
+ blocks.pop_back();
/* We've found another train. If it wants to exit the block from the
same endpoint we're trying to enter from or the other way around,
treat it as coming towards us. Otherwise treat it as going in the
/* Ask a lesser priority train going to the same direction to free
the block for us */
if(other_train->free_block(*block))
- reserved = block->reserve(this);
+ {
+ blocks.push_back(block);
+ if(!(reserved = block->reserve(this)))
+ blocks.pop_back();
+ }
}
else if(other_train!=yielding_to && (other_prio<priority || (other_prio==priority && entry_conflict)))
{
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();
- blocks.push_back(block);
-
if(cur_blocks_end==blocks.end())
--cur_blocks_end;
if(clear_blocks_end==blocks.end())
// 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)
if(i==clear_blocks_end)
++clear_blocks_end;
+ if(i==cur_blocks_end && !(*i)->get_sensor_id())
+ ++cur_blocks_end;
}
}
*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),
if(entry<0)
entry = 0;
- blk->reserve(&obj);
obj.blocks.push_back(BlockIter(blk, entry));
+ blk->reserve(&obj);
if(blk->get_sensor_id())
obj.layout.get_driver().set_sensor(blk->get_sensor_id(), true);