5 #include "trainrouter.h"
13 TrainRouter::TrainRouter(Train &t):
19 train.get_layout().signal_block_reserved.connect(sigc::mem_fun(this, &TrainRouter::block_reserved));
20 train.signal_advanced.connect(sigc::mem_fun(this, &TrainRouter::train_advanced));
23 void TrainRouter::set_priority(int p)
28 void TrainRouter::yield_to(const Train &t)
33 bool TrainRouter::set_route(const Route *r)
35 train.free_noncritical_blocks();
38 if(r && train.is_placed())
40 TrackIter first = train.get_tail_block().track_iter();
41 TrackIter next = train.get_head_block().next().track_iter();
42 if(!r->has_track(*next))
44 lead = Route::find(next, *r);
47 create_lead_route(lead, lead);
49 else if(!r->has_track(*first))
50 lead = create_lead_route(0, r);
55 routes.push_back(lead);
63 const Route *route = get_route();
64 signal_route_changed.emit(route);
65 signal_event.emit(Message("route-changed", route));
70 bool TrainRouter::go_to(Track &to)
72 if(!train.get_speed())
74 for(BlockIter i=train.get_tail_block(); (i && i->get_train()==&train); i=i.next())
77 signal_arrived.emit();
78 signal_event.emit(Message("arrived"));
83 train.free_noncritical_blocks();
85 TrackIter next = train.get_head_block().next().track_iter();
87 Route *route = Route::find(next, to);
90 create_lead_route(route, route);
91 return set_route(route);
94 bool TrainRouter::go_to(const Zone &to)
97 for(BlockIter i=train.get_tail_block(); (i && i->get_train()==&train); i=i.next())
98 tracks.insert(i->get_tracks().begin(), i->get_tracks().end());
100 const Zone::TrackSet &ztracks = to.get_tracks();
101 unsigned union_size = 0;
102 for(Zone::TrackSet::const_iterator i=ztracks.begin(); i!=ztracks.end(); ++i)
103 union_size += tracks.count(*i);
105 if(union_size==tracks.size() || union_size==ztracks.size())
107 signal_arrived.emit();
108 signal_event.emit(Message("arrived"));
112 train.free_noncritical_blocks();
114 TrackIter next = train.get_head_block().next().track_iter();
116 Route *route = Route::find(next, to);
119 create_lead_route(route, route);
120 route->add_tracks(ztracks);
121 return set_route(route);
124 const Route *TrainRouter::get_route() const
128 return routes.front();
131 void TrainRouter::message(const Message &msg)
133 if(msg.type=="set-route")
135 if(msg.value.check_type<Route *>())
136 set_route(msg.value.value<Route *>());
138 set_route(msg.value.value<const Route *>());
140 else if(msg.type=="clear-route")
142 else if(msg.type=="go-to-track")
143 go_to(*msg.value.value<Track *>());
144 else if(msg.type=="go-to-zone")
146 if(msg.value.check_type<Zone *>())
147 go_to(*msg.value.value<Zone *>());
149 go_to(*msg.value.value<const Zone *>());
153 void TrainRouter::tick(const Time::TimeStamp &, const Time::TimeDelta &)
155 if(arriving && !train.get_speed())
157 train.set_active(false);
158 signal_arrived.emit();
159 signal_event.emit(Message("arrived"));
164 void TrainRouter::save(list<DataFile::Statement> &st) const
167 st.push_back((DataFile::Statement("tag"), tag));
169 st.push_back((DataFile::Statement("priority"), priority));
173 RouteList::const_iterator i = routes.begin();
174 for(; (i!=routes.end() && (*i)->is_temporary()); ++i) ;
176 st.push_back((DataFile::Statement("route"), (*i)->get_name()));
180 void TrainRouter::block_reserved(Block &block, Train *t)
187 BlockIter b_iter(&block, t->get_entry_to_block(block));
188 BlockIter b_iter_next;
190 RouteList::iterator route = routes.begin();
191 if(advance_route(route, block))
193 // Check if the block is a turnout and set it to proper path
194 if(unsigned tid = block.get_turnout_id())
196 int path = (*route)->get_turnout(tid);
198 b_iter.track_iter()->set_active_path(path);
201 // Check if the next block is still part of the designated route
202 b_iter_next = b_iter.next(*route);
204 RouteList::iterator next_route = route;
205 if(!advance_route(next_route, *b_iter_next))
207 train.stop_at(&block);
213 b_iter_next = b_iter.next();
215 // Check if there's another train and ask it to free the block if appropriate
218 if(Train *other_train = b_iter_next->get_train())
220 /* There's another train ahead of us. If it wants to exit the block
221 from the same endpoint we're trying to enter from or the other way
222 around, treat it as coming towards us. Otherwise treat it as going
223 in the same direction. */
224 int other_entry = other_train->get_entry_to_block(*b_iter_next);
226 throw logic_error("block reservation inconsistency");
228 unsigned exit = b_iter_next.reverse().entry();
229 unsigned other_exit = BlockIter(b_iter_next.block(), other_entry).reverse().entry();
230 bool entry_conflict = (b_iter_next.entry()==other_exit);
231 bool exit_conflict = (exit==static_cast<unsigned>(other_entry));
232 // TODO: speed matching with preceding train
234 // XXX Should invent a better way to get our counterpart from the other train
235 TrainRouter *other_router = dynamic_cast<TrainRouter *>(other_train->get_tagged_ai("router"));
236 int other_prio = (other_router ? other_router->get_priority() : 0);
238 if(!entry_conflict && !exit_conflict && other_prio<priority)
240 /* Ask a lesser priority train going to the same direction to free
242 other_train->free_block(*b_iter_next);
244 else if(other_train!=yielding_to && (other_prio<priority || (other_prio==priority && entry_conflict)))
246 /* A lesser priority train is coming at us, we must ask it to free
247 enough blocks to get clear of it to avoid a potential deadlock */
248 BlockIter last_contested;
249 RouteList::iterator j = route;
250 for(BlockIter i=b_iter_next; (i && i->get_train()==other_train);)
252 if(!advance_route(j, *i))
260 if(other_train->free_block(*last_contested))
261 other_router->yield_to(train);
263 yield_to(*other_train);
270 void TrainRouter::train_advanced(Block &block)
272 // Check if we've reached the next route
275 unsigned entry = train.get_entry_to_block(block);
276 Track &track = *block.get_endpoint(entry).track;
277 const Route &route = **++routes.begin();
278 if(route.has_track(track))
282 signal_event.emit(Message("route-changed", get_route()));
286 BlockIter iter(&block, train.get_entry_to_block(block));
288 if(iter && !is_on_route(*iter))
292 const Route *TrainRouter::get_route_for_block(const Block &block) const
294 const set<Track *> &tracks = block.get_tracks();
295 for(RouteList::const_iterator i=routes.begin(); i!=routes.end(); ++i)
296 for(set<Track *>::const_iterator j=tracks.begin(); j!=tracks.end(); ++j)
297 if((*i)->has_track(**j))
303 Route *TrainRouter::create_lead_route(Route *lead, const Route *target)
307 lead = new Route(train.get_layout());
308 lead->set_name("Lead");
309 lead->set_temporary(true);
313 for(BlockIter i=train.get_tail_block(); (i && i->get_train()==&train); i=i.next())
315 const set<Track *> &btracks = i->get_tracks();
316 for(set<Track *>::const_iterator j=btracks.begin(); j!=btracks.end(); ++j)
317 if(!target || !target->has_track(**j))
321 lead->add_tracks(tracks);
326 bool TrainRouter::advance_route(RouteList::iterator &iter, const Block &block)
328 const set<Track *> &tracks = block.get_tracks();
329 for(; iter!=routes.end(); ++iter)
330 for(set<Track *>::const_iterator j=tracks.begin(); j!=tracks.end(); ++j)
331 if((*iter)->has_track(**j))
337 bool TrainRouter::is_on_route(const Block &block)
339 RouteList::iterator iter = routes.begin();
340 return advance_route(iter, block);
344 TrainRouter::Loader::Loader(TrainRouter &r):
345 DataFile::ObjectLoader<TrainRouter>(r)
347 add("priority", &TrainRouter::priority);
348 add("route", &Loader::route);
349 add("tag", &Loader::tag);
352 void TrainRouter::Loader::route(const string &n)
354 obj.set_route(&obj.train.get_layout().get_route(n));
357 void TrainRouter::Loader::tag(const string &t)