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
166 st.push_back((DataFile::Statement("priority"), priority));
170 RouteList::const_iterator i = routes.begin();
171 for(; (i!=routes.end() && (*i)->is_temporary()); ++i) ;
173 st.push_back((DataFile::Statement("route"), (*i)->get_name()));
177 void TrainRouter::block_reserved(Block &block, Train *t)
184 BlockIter b_iter(&block, t->get_entry_to_block(block));
185 BlockIter b_iter_next;
187 RouteList::iterator route = routes.begin();
188 if(advance_route(route, block))
190 // Check if the block is a turnout and set it to proper path
191 if(unsigned tid = block.get_turnout_id())
193 int path = (*route)->get_turnout(tid);
195 b_iter.track_iter()->set_active_path(path);
198 // Check if the next block is still part of the designated route
199 b_iter_next = b_iter.next(*route);
201 RouteList::iterator next_route = route;
202 if(!advance_route(next_route, *b_iter_next))
204 train.stop_at(&block);
210 b_iter_next = b_iter.next();
212 // Check if there's another train and ask it to free the block if appropriate
215 if(Train *other_train = b_iter_next->get_train())
217 /* There's another train ahead of us. If it wants to exit the block
218 from the same endpoint we're trying to enter from or the other way
219 around, treat it as coming towards us. Otherwise treat it as going
220 in the same direction. */
221 int other_entry = other_train->get_entry_to_block(*b_iter_next);
223 throw logic_error("block reservation inconsistency");
225 unsigned exit = b_iter_next.reverse().entry();
226 unsigned other_exit = BlockIter(b_iter_next.block(), other_entry).reverse().entry();
227 bool entry_conflict = (b_iter_next.entry()==other_exit);
228 bool exit_conflict = (exit==static_cast<unsigned>(other_entry));
229 // TODO: speed matching with preceding train
231 TrainRouter *other_router = other_train->get_ai_of_type<TrainRouter>();
232 int other_prio = (other_router ? other_router->get_priority() : 0);
234 if(!entry_conflict && !exit_conflict && other_prio<priority)
236 /* Ask a lesser priority train going to the same direction to free
238 other_train->free_block(*b_iter_next);
240 else if(other_train!=yielding_to && (other_prio<priority || (other_prio==priority && entry_conflict)))
242 /* A lesser priority train is coming at us, we must ask it to free
243 enough blocks to get clear of it to avoid a potential deadlock */
244 BlockIter last_contested;
245 RouteList::iterator j = route;
246 for(BlockIter i=b_iter_next; (i && i->get_train()==other_train);)
248 if(!advance_route(j, *i))
256 if(other_train->free_block(*last_contested))
257 other_router->yield_to(train);
259 yield_to(*other_train);
266 void TrainRouter::train_advanced(Block &block)
268 // Check if we've reached the next route
271 unsigned entry = train.get_entry_to_block(block);
272 Track &track = *block.get_endpoint(entry).track;
273 const Route &route = **++routes.begin();
274 if(route.has_track(track))
278 signal_event.emit(Message("route-changed", get_route()));
284 BlockIter iter(&block, train.get_entry_to_block(block));
286 if(iter && !is_on_route(*iter))
291 const Route *TrainRouter::get_route_for_block(const Block &block) const
293 const set<Track *> &tracks = block.get_tracks();
294 for(RouteList::const_iterator i=routes.begin(); i!=routes.end(); ++i)
295 for(set<Track *>::const_iterator j=tracks.begin(); j!=tracks.end(); ++j)
296 if((*i)->has_track(**j))
302 Route *TrainRouter::create_lead_route(Route *lead, const Route *target)
306 lead = new Route(train.get_layout());
307 lead->set_name("Lead");
308 lead->set_temporary(true);
312 for(BlockIter i=train.get_tail_block(); (i && i->get_train()==&train); i=i.next())
314 const set<Track *> &btracks = i->get_tracks();
315 for(set<Track *>::const_iterator j=btracks.begin(); j!=btracks.end(); ++j)
316 if(!target || !target->has_track(**j))
320 lead->add_tracks(tracks);
325 bool TrainRouter::advance_route(RouteList::iterator &iter, const Block &block)
327 const set<Track *> &tracks = block.get_tracks();
328 for(; iter!=routes.end(); ++iter)
329 for(set<Track *>::const_iterator j=tracks.begin(); j!=tracks.end(); ++j)
330 if((*iter)->has_track(**j))
336 bool TrainRouter::is_on_route(const Block &block)
338 RouteList::iterator iter = routes.begin();
339 return advance_route(iter, block);
343 TrainRouter::Loader::Loader(TrainRouter &r):
344 DataFile::ObjectLoader<TrainRouter>(r)
346 add("priority", &TrainRouter::priority);
347 add("route", &Loader::route);
350 void TrainRouter::Loader::route(const string &n)
352 obj.set_route(&obj.train.get_layout().get_route(n));