3 This file is part of R²C²
4 Copyright © 2006-2011 Mikkosoft Productions, Mikko Rasa
5 Distributed under the GPL
9 #include <msp/strings/formatter.h>
10 #include <msp/time/units.h>
11 #include <msp/time/utils.h>
12 #include "aicontrol.h"
13 #include "catalogue.h"
17 #include "simplecontroller.h"
18 #include "speedquantizer.h"
19 #include "timetable.h"
20 #include "trackiter.h"
21 #include "tracktype.h"
24 #include "vehicletype.h"
36 SetFlag(bool &f): flag(f) { flag = true; }
37 ~SetFlag() { flag = false; }
45 Train::Train(Layout &l, const VehicleType &t, unsigned a, const string &p):
53 cur_blocks_end(blocks.end()),
54 clear_blocks_end(blocks.end()),
58 controller(new AIControl(*this, new SimpleController)),
61 current_speed_step(0),
62 speed_changing(false),
70 accurate_position(false),
73 if(!loco_type.is_locomotive())
74 throw InvalidParameterValue("Initial vehicle must be a locomotive");
76 unsigned speed_steps = layout.get_driver().get_protocol_speed_steps(protocol);
78 speed_quantizer = new SpeedQuantizer(speed_steps);
80 vehicles.push_back(new Vehicle(layout, loco_type));
82 layout.add_train(*this);
84 layout.get_driver().add_loco(address, protocol, loco_type);
85 layout.get_driver().signal_loco_speed.connect(sigc::mem_fun(this, &Train::loco_speed_event));
86 layout.get_driver().signal_loco_function.connect(sigc::mem_fun(this, &Train::loco_func_event));
88 layout.signal_block_reserved.connect(sigc::mem_fun(this, &Train::block_reserved));
89 layout.get_driver().signal_sensor.connect(sigc::mem_fun(this, &Train::sensor_event));
91 layout.get_driver().signal_halt.connect(sigc::mem_fun(this, &Train::halt_event));
93 const set<Track *> &tracks = layout.get_tracks();
94 for(set<Track *>::const_iterator i=tracks.begin(); i!=tracks.end(); ++i)
95 if((*i)->get_turnout_id())
96 (*i)->signal_path_changed.connect(sigc::hide(sigc::bind(sigc::mem_fun(this, &Train::turnout_path_changed), sigc::ref(**i))));
98 controller->signal_control_changed.connect(sigc::mem_fun(this, &Train::control_changed));
105 for(vector<Vehicle *>::iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
107 layout.remove_train(*this);
110 void Train::set_name(const string &n)
114 signal_name_changed.emit(name);
117 void Train::set_priority(int p)
122 void Train::yield_to(const Train &t)
127 void Train::add_vehicle(const VehicleType &vt)
129 Vehicle *veh = new Vehicle(layout, vt);
130 vehicles.back()->attach_back(*veh);
131 vehicles.push_back(veh);
134 void Train::remove_vehicle(unsigned i)
136 if(i>=vehicles.size())
137 throw InvalidParameterValue("Vehicle index out of range");
139 throw InvalidParameterValue("Can't remove the locomotive");
141 vehicles.erase(vehicles.begin()+i);
142 if(i<vehicles.size())
143 vehicles[i-1]->attach_back(*vehicles[i]);
146 unsigned Train::get_n_vehicles() const
148 return vehicles.size();
151 Vehicle &Train::get_vehicle(unsigned i)
153 if(i>=vehicles.size())
154 throw InvalidParameterValue("Vehicle index out of range");
158 const Vehicle &Train::get_vehicle(unsigned i) const
160 if(i>=vehicles.size())
161 throw InvalidParameterValue("Vehicle index out of range");
165 void Train::set_control(const string &n, float v)
167 controller->set_control(n, v);
170 void Train::set_active(bool a)
174 if(!a && controller->get_speed())
175 throw InvalidState("Can't deactivate while moving");
180 stop_timeout = Time::TimeStamp();
185 stop_timeout = Time::now()+2*Time::sec;
186 set_status("Stopped");
190 void Train::set_function(unsigned func, bool state)
192 if(!loco_type.get_functions().count(func))
193 throw InvalidParameterValue("Invalid function");
194 layout.get_driver().set_loco_function(address, func, state);
197 float Train::get_control(const string &ctrl) const
199 return controller->get_control(ctrl).value;
202 float Train::get_speed() const
204 return controller->get_speed();
207 bool Train::get_function(unsigned func) const
209 return (functions>>func)&1;
212 void Train::set_timetable(Timetable *tt)
218 bool Train::set_route(const Route *r)
220 free_noncritical_blocks();
223 if(r && !blocks.empty())
225 TrackIter first = blocks.front().track_iter();
226 TrackIter next = blocks.back().next().track_iter();
227 if(!r->has_track(*next))
229 lead = Route::find(next, *r);
232 create_lead_route(lead, lead);
233 routes.push_front(lead);
235 else if(!r->has_track(*first))
236 lead = create_lead_route(0, r);
241 routes.push_back(lead);
244 end_of_route = false;
248 signal_route_changed.emit(get_route());
253 bool Train::go_to(Track &to)
255 for(BlockList::const_iterator i=blocks.begin(); i!=cur_blocks_end; ++i)
256 if((*i)->has_track(to))
258 signal_arrived.emit();
262 free_noncritical_blocks();
264 TrackIter next = blocks.back().next().track_iter();
266 Route *route = Route::find(next, to);
269 create_lead_route(route, route);
270 return set_route(route);
273 bool Train::go_to(const Zone &to)
276 for(BlockList::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
277 tracks.insert((*i)->get_tracks().begin(), (*i)->get_tracks().end());
279 const Zone::TrackSet &ztracks = to.get_tracks();
280 unsigned union_size = 0;
281 for(Zone::TrackSet::const_iterator i=ztracks.begin(); i!=ztracks.end(); ++i)
282 union_size += tracks.count(*i);
284 if(union_size==tracks.size() || union_size==ztracks.size())
286 signal_arrived.emit();
290 free_noncritical_blocks();
292 TrackIter next = blocks.back().next().track_iter();
294 Route *route = Route::find(next, to);
297 create_lead_route(route, route);
298 route->add_tracks(ztracks);
299 return set_route(route);
302 bool Train::divert(Track &from)
304 if(!from.get_turnout_id())
305 throw InvalidParameterValue("Can't divert from a non-turnout");
311 list<RouteRef>::iterator route = routes.begin();
313 // Follow our routes to find out where we're entering the turnout
314 for(TrackLoopIter track = blocks.front().track_iter();;)
316 if(!advance_route(route, *track))
321 Block &block = track->get_block();
322 if(block.get_train()==this && !free_block(block))
325 int route_path = route->route->get_turnout(from.get_turnout_id());
327 // Check that more than one path is available
328 unsigned ep_paths = track.endpoint().paths;
329 if(!(ep_paths&(ep_paths-1)))
332 // Choose some other path
333 for(int i=0; ep_paths>>i; ++i)
334 if((ep_paths&(1<<i)) && i!=route_path)
340 entry = track.entry();
344 track = track.next(route->route->get_path(*track));
346 if(!track || track.looped())
350 TrackIter track = TrackIter(&from, entry).next(path);
355 for(list<RouteRef>::iterator i=routes.begin(); i!=routes.end(); ++i)
356 tracks.insert(i->route->get_tracks().begin(), i->route->get_tracks().end());
357 RefPtr<Route> diversion = Route::find(track, tracks);
361 diversion->set_name("Diversion");
362 diversion->add_track(from);
363 diversion->set_turnout(from.get_turnout_id(), path);
365 if(!is_valid_diversion(*diversion, TrackIter(&from, entry)))
368 // Follow the diversion route until we get back to the original route
369 list<RouteRef>::iterator end = routes.end();
372 for(list<RouteRef>::iterator i=route; (end==routes.end() && i!=routes.end()); ++i)
373 if(i->route->has_track(*track))
376 if(end!=routes.end())
378 else if(!diversion->has_track(*track))
379 throw LogicError("Pathfinder returned a bad route");
381 track = track.next(diversion->get_path(*track));
385 // We are rejoining the same route we diverted from, duplicate it
386 routes.insert(end, *route);
390 routes.erase(route, end);
392 routes.insert(end, RouteRef(diversion.release(), from.get_turnout_id()));
397 const Route *Train::get_route() const
401 return routes.front().route;
404 void Train::place(Block &block, unsigned entry)
406 if(controller->get_speed())
407 throw InvalidState("Must be stopped before placing");
412 accurate_position = false;
414 if(!block.reserve(this))
416 set_status("Unplaced");
420 blocks.push_back(BlockIter(&block, entry));
423 TrackIter track = BlockIter(&block, entry).reverse().track_iter();
424 vehicles.front()->place(*track, track.entry(), 0, Vehicle::FRONT_BUFFER);
428 const Block::Endpoint &bep = block.get_endpoint(entry);
429 vehicles.back()->place(*bep.track, bep.track_ep, 0, Vehicle::BACK_BUFFER);
433 void Train::unplace()
435 if(controller->get_speed())
436 throw InvalidState("Must be stopped before unplacing");
441 accurate_position = false;
443 for(vector<Vehicle *>::iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
446 set_status("Unplaced");
449 bool Train::free_block(Block &block)
451 if(get_reserved_distance_until(&block, false)<controller->get_braking_distance()*1.3)
455 for(BlockList::iterator i=cur_blocks_end; i!=blocks.end(); ++i)
457 if(i->block()==&block)
461 release_blocks(i, blocks.end());
464 else if((*i)->get_sensor_id())
471 void Train::free_noncritical_blocks()
476 if(controller->get_speed()==0)
478 release_blocks(cur_blocks_end, blocks.end());
482 float margin = 10*layout.get_catalogue().get_scale();
483 float min_dist = controller->get_braking_distance()*1.3+margin;
485 Vehicle &veh = *(reverse ? vehicles.back() : vehicles.front());
487 TrackIter track(veh.get_track(), veh.get_entry());
488 BlockList::iterator block = blocks.begin();
490 while(block!=blocks.end() && !(*block)->has_track(*track))
493 if(block==cur_blocks_end)
497 float dist = veh.get_offset();
501 dist = track->get_type().get_path_length(track->get_active_path())-dist;
502 dist -= veh.get_type().get_length()/2;
507 track = track.next();
509 if(!(*block)->has_track(*track))
512 if(block==cur_blocks_end)
514 if(block==blocks.end())
517 if(dist>min_dist && nsens>0)
519 release_blocks(block, blocks.end());
523 if(in_rsv && (*block)->get_sensor_id())
527 dist += track->get_type().get_path_length(track->get_active_path());
531 int Train::get_entry_to_block(Block &block) const
533 for(BlockList::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
534 if(i->block()==&block)
539 float Train::get_reserved_distance() const
545 TrackIter next = blocks.back().next().track_iter();
546 if(next && next->get_type().is_turnout())
547 margin = 15*layout.get_catalogue().get_scale();
549 return max(get_reserved_distance_until(0, false)-margin, 0.0f);
552 void Train::tick(const Time::TimeStamp &t, const Time::TimeDelta &dt)
554 if(!active && stop_timeout && t>=stop_timeout)
556 release_blocks(cur_blocks_end, blocks.end());
557 stop_timeout = Time::TimeStamp();
560 Driver &driver = layout.get_driver();
564 controller->tick(dt);
565 float speed = controller->get_speed();
567 if(controller->get_reverse()!=reverse)
569 reverse = controller->get_reverse();
570 driver.set_loco_reverse(address, reverse);
572 release_blocks(cur_blocks_end, blocks.end());
573 reverse_blocks(blocks);
580 unsigned speed_step = speed_quantizer->find_speed_step(speed);
581 if(speed_step!=current_speed_step && !speed_changing && !driver.is_halted() && driver.get_power())
583 speed_changing = true;
584 driver.set_loco_speed(address, speed_step);
589 set_status(format("Traveling %d kmh", get_travel_speed()));
591 set_status("Waiting");
594 speed = speed_quantizer->get_speed(current_speed_step);
602 Vehicle &vehicle = *(reverse ? vehicles.back() : vehicles.front());
603 Track *track = vehicle.get_track();
606 for(BlockList::const_iterator i=blocks.begin(); (!ok && i!=cur_blocks_end); ++i)
607 ok = (*i)->has_track(*track);
609 float d = speed*(dt/Time::sec);
612 SetFlag setf(advancing);
613 vehicle.advance(reverse ? -d : d);
615 else if(accurate_position)
618 if(overshoot_dist>40*layout.get_catalogue().get_scale())
620 layout.emergency(name+" has not arrived at sensor");
621 accurate_position = false;
625 else if(end_of_route && cur_blocks_end==blocks.end())
628 signal_arrived.emit();
632 if(!blocks.empty() && !blocks.front()->get_sensor_id())
634 float dist = get_reserved_distance_until(&*blocks.front(), true);
636 if(dist>10*layout.get_catalogue().get_scale())
638 blocks.front()->reserve(0);
644 void Train::save(list<DataFile::Statement> &st) const
646 st.push_back((DataFile::Statement("name"), name));
648 st.push_back((DataFile::Statement("priority"), priority));
650 for(vector<Vehicle *>::const_iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
651 if(i!=vehicles.begin())
652 st.push_back((DataFile::Statement("vehicle"), (*i)->get_type().get_article_number()));
656 DataFile::Statement ss("quantized_speed");
657 speed_quantizer->save(ss.sub);
661 if(!blocks.empty() && cur_blocks_end!=blocks.begin())
663 BlockList blks(blocks.begin(), BlockList::const_iterator(cur_blocks_end));
665 reverse_blocks(blks);
667 BlockIter prev = blks.front().flip();
668 st.push_back((DataFile::Statement("block_hint"), prev->get_id()));
670 for(BlockList::const_iterator i=blks.begin(); i!=blks.end(); ++i)
671 st.push_back((DataFile::Statement("block"), (*i)->get_id()));
676 list<RouteRef>::const_iterator i = routes.begin();
677 for(; (i!=routes.end() && i->route->is_temporary()); ++i) ;
679 st.push_back((DataFile::Statement("route"), i->route->get_name()));
684 DataFile::Statement ss("timetable");
685 timetable->save(ss.sub);
690 void Train::control_changed(const Controller::Control &ctrl)
692 signal_control_changed.emit(ctrl.name, ctrl.value);
695 void Train::loco_speed_event(unsigned addr, unsigned speed, bool rev)
699 current_speed_step = speed;
701 layout.get_driver().set_loco_reverse(address, reverse);
702 speed_changing = false;
707 void Train::loco_func_event(unsigned addr, unsigned func, bool state)
712 functions |= 1<<func;
714 functions &= ~(1<<func);
716 signal_function_changed.emit(func, state);
720 void Train::sensor_event(unsigned addr, bool state)
724 // Find the first sensor block from our reserved blocks that isn't this sensor
725 BlockList::iterator end;
727 for(end=cur_blocks_end; end!=blocks.end(); ++end)
728 if((*end)->get_sensor_id())
730 if((*end)->get_sensor_id()!=addr)
745 // Compute speed and update related state
746 float travel_time_secs = (Time::now()-last_entry_time)/Time::sec;
750 if(speed_quantizer && current_speed_step>0)
751 speed_quantizer->learn(current_speed_step, travel_dist/travel_time_secs, travel_time_secs);
752 set_status(format("Traveling %d kmh", get_travel_speed()));
756 for(BlockList::iterator j=cur_blocks_end; j!=end; ++j)
758 travel_dist += (*j)->get_path_length(j->entry());
760 if((*j)->get_sensor_id()==addr && !advancing)
762 TrackIter track = j->track_iter();
765 track = track.flip();
766 vehicles.back()->place(*track, track.entry(), 0, Vehicle::BACK_AXLE);
769 vehicles.front()->place(*track, track.entry(), 0, Vehicle::FRONT_AXLE);
772 last_entry_time = Time::now();
774 accurate_position = true;
777 // Check if we've reached the next route
780 const Route &route = *(++routes.begin())->route;
781 for(BlockList::iterator j=cur_blocks_end; j!=end; ++j)
782 if(route.has_track(*j->track_iter()))
786 signal_route_changed.emit(routes.front().route);
791 // Move blocks up to the next sensor to our current blocks
792 for(BlockList::iterator j=cur_blocks_end; j!=end; ++j)
793 signal_advanced.emit(**j);
794 cur_blocks_end = end;
796 // Try to get more blocks if we're moving
801 layout.emergency("Sensor for "+name+" triggered out of order");
805 const Vehicle &veh = *(reverse ? vehicles.front() : vehicles.back());
807 // Find the first sensor in our current blocks that's still active
808 BlockList::iterator end = blocks.begin();
809 for(BlockList::iterator i=blocks.begin(); i!=cur_blocks_end; ++i)
811 if((*i)->has_track(*veh.get_track()))
813 if((*i)->get_sensor_id())
815 if(layout.get_driver().get_sensor((*i)->get_sensor_id()))
825 if(end!=blocks.begin() && end!=cur_blocks_end)
826 // Free blocks up to the last inactive sensor
827 release_blocks(blocks.begin(), end);
831 void Train::turnout_path_changed(Track &track)
833 for(list<BlockIter>::iterator i=blocks.begin(); i!=blocks.end(); ++i)
834 if((*i)->get_turnout_id()==track.get_turnout_id() && !reserving)
835 check_turnout_paths(false);
838 void Train::halt_event(bool h)
841 accurate_position = false;
844 void Train::block_reserved(const Block &block, const Train *train)
846 if(&block==pending_block && !train && !reserving)
850 void Train::reserve_more()
852 if(!active || blocks.empty() || end_of_route)
855 BlockIter start = blocks.back();
860 // See how many sensor blocks and how much track we already have
863 for(BlockList::const_iterator i=cur_blocks_end; i!=blocks.end(); ++i)
865 if((*i)->get_sensor_id())
868 dist += (*i)->get_path_length(i->entry());
871 list<RouteRef>::iterator cur_route = routes.begin();
872 advance_route(cur_route, *start.track_iter());
874 float approach_margin = 50*layout.get_catalogue().get_scale();
875 float min_dist = controller->get_braking_distance()*1.3+approach_margin*2;
877 BlockIter block = start;
878 list<BlockIter>::iterator good_end = blocks.end();
879 Track *divert_track = 0;
880 bool try_divert = false;
881 Train *blocking_train = 0;
882 BlockList contested_blocks;
884 SetFlag setf(reserving);
888 BlockIter last = block;
889 block = block.next(cur_route!=routes.end() ? cur_route->route : 0);
890 if(!block || block->get_endpoints().size()<2)
894 good_end = blocks.end();
900 TrackIter track = block.track_iter();
902 if(cur_route!=routes.end())
904 if(!advance_route(cur_route, *track))
906 // Keep the blocks if we arrived at the end of the route
909 good_end = blocks.end();
916 if(block->get_turnout_id() && !last->get_turnout_id())
918 /* We can keep the blocks if we arrive at a turnout from a non-turnout
919 block. Having a turnout block as our last reserved block is not good
920 as it would limit our diversion possibilities for little benefit. */
921 good_end = blocks.end();
922 if(nsens>=3 && dist>=min_dist)
928 if(block->get_train()!=blocking_train)
930 if(blocking_train->free_block(*contested_blocks.back()))
932 // Roll back and start actually reserving the blocks
933 block = blocks.back();
934 cur_route = routes.begin();
935 advance_route(cur_route, *block.track_iter().track());
936 if(blocking_train->get_priority()==priority)
937 blocking_train->yield_to(*this);
943 yield_to(*blocking_train);
944 pending_block = contested_blocks.front().block();
945 try_divert = divert_track;
951 contested_blocks.push_back(block);
956 bool reserved = block->reserve(this);
959 /* We've found another train. If it wants to exit the block from the
960 same endpoint we're trying to enter from or the other way around,
961 treat it as coming towards us. Otherwise treat it as going in the
963 Train *other_train = block->get_train();
964 int other_entry = other_train->get_entry_to_block(*block);
966 throw LogicError("Block reservation inconsistency");
968 unsigned exit = block.reverse().entry();
969 unsigned other_exit = BlockIter(block.block(), other_entry).reverse().entry();
970 bool entry_conflict = (block.entry()==other_exit);
971 bool exit_conflict = (exit==static_cast<unsigned>(other_entry));
972 if(!entry_conflict && !last->get_turnout_id())
974 /* The other train is not coming to the blocks we're holding, so we
976 good_end = blocks.end();
978 if(static_cast<unsigned>(other_entry)==block.entry())
979 preceding_train = other_train;
982 int other_prio = other_train->get_priority();
984 if(!entry_conflict && !exit_conflict && other_prio<priority)
986 /* Ask a lesser priority train going to the same direction to free
988 if(other_train->free_block(*block))
989 reserved = block->reserve(this);
991 else if(other_train!=yielding_to && (other_prio<priority || (other_prio==priority && entry_conflict)))
993 /* A lesser priority train is coming at us, we must ask it to free
994 enough blocks to get clear of it to avoid a potential deadlock */
995 blocking_train = other_train;
996 contested_blocks.clear();
997 contested_blocks.push_back(block);
1000 else if(divert_track && (entry_conflict || exit_conflict || !other_train->is_active()))
1001 // We are blocked, but there's a diversion possibility
1006 pending_block = &*block;
1011 if(block->get_turnout_id())
1013 const TrackType::Endpoint &track_ep = track.endpoint();
1014 bool multiple_paths = (track_ep.paths&(track_ep.paths-1));
1016 if(multiple_paths && cur_route!=routes.end() && cur_route->diversion!=block->get_turnout_id())
1017 /* There's multiple paths to be taken and we are on a route - take
1018 note of the diversion possibility */
1019 divert_track = &*track;
1022 if(!contested_blocks.empty() && contested_blocks.front()==block)
1023 contested_blocks.pop_front();
1025 blocks.push_back(block);
1027 if(cur_blocks_end==blocks.end())
1029 if(clear_blocks_end==blocks.end())
1031 if(good_end==blocks.end())
1034 if(block->get_sensor_id())
1037 dist += block->get_path_length(block.entry());
1040 // Unreserve blocks that were not good
1041 release_blocks(good_end, blocks.end());
1043 if(blocks.back()!=start)
1044 // We got some new blocks, so no longer need to yield
1047 check_turnout_paths(true);
1049 // Make any sensorless blocks at the beginning immediately current
1050 while(cur_blocks_end!=clear_blocks_end && !(*cur_blocks_end)->get_sensor_id())
1053 if(try_divert && divert(*divert_track))
1057 void Train::check_turnout_paths(bool set)
1059 if(clear_blocks_end==blocks.end())
1062 for(list<BlockIter>::iterator i=clear_blocks_end; i!=blocks.end(); ++i)
1064 if((*i)->get_turnout_id())
1066 TrackIter track = i->track_iter();
1067 const TrackType::Endpoint &track_ep = track.endpoint();
1070 list<BlockIter>::iterator j = i;
1071 if(++j!=blocks.end())
1073 TrackIter rev = j->track_iter().flip();
1074 unsigned mask = rev.endpoint().paths&track_ep.paths;
1075 for(path=0; mask>1; mask>>=1, ++path) ;
1080 if(path!=track->get_active_path())
1083 track->set_active_path(path);
1085 /* Check again, in case the driver was able to service the request
1087 if(!set || path!=track->get_active_path())
1092 if(i==clear_blocks_end)
1097 float Train::get_reserved_distance_until(const Block *until_block, bool back) const
1102 Vehicle &veh = *(reverse!=back ? vehicles.back() : vehicles.front());
1103 const VehicleType &vtype = veh.get_type();
1105 TrackIter track(veh.get_track(), veh.get_entry());
1106 if(!track) // XXX Probably unnecessary
1109 BlockList::const_iterator block = blocks.begin();
1110 while(block!=clear_blocks_end && !(*block)->has_track(*track))
1112 if(block==clear_blocks_end || &**block==until_block)
1115 float result = veh.get_offset();
1117 track = track.reverse();
1119 result = track->get_type().get_path_length(track->get_active_path())-result;
1120 result -= vtype.get_length()/2;
1124 track = track.next();
1128 if(!(*block)->has_track(*track))
1132 if(block==blocks.begin())
1139 if(block==clear_blocks_end)
1143 if(&**block==until_block)
1147 result += track->get_type().get_path_length(track->get_active_path());
1153 float Train::get_travel_speed() const
1157 speed = speed_quantizer->get_speed(current_speed_step);
1159 speed = controller->get_speed();
1160 float scale = layout.get_catalogue().get_scale();
1161 return static_cast<int>(round(speed/scale*3.6/5))*5;
1164 void Train::set_status(const string &s)
1167 signal_status_changed.emit(s);
1170 void Train::release_blocks()
1172 release_blocks(blocks.begin(), blocks.end());
1175 void Train::release_blocks(BlockList::iterator begin, BlockList::iterator end)
1179 if(begin==cur_blocks_end)
1180 cur_blocks_end = end;
1181 if(begin==clear_blocks_end)
1182 clear_blocks_end = end;
1184 Block &block = **begin;
1185 blocks.erase(begin++);
1188 if(begin==blocks.end())
1189 end_of_route = false;
1193 void Train::reverse_blocks(BlockList &blks) const
1196 for(BlockList::iterator i=blks.begin(); i!=blks.end(); ++i)
1200 bool Train::advance_route(list<RouteRef>::iterator &iter, Track &track)
1202 while(iter!=routes.end() && !iter->route->has_track(track))
1204 if(iter==routes.end())
1207 list<RouteRef>::iterator next = iter;
1209 if(next!=routes.end() && next->diversion && next->route->has_track(track))
1215 Route *Train::create_lead_route(Route *lead, const Route *target)
1219 lead = new Route(layout);
1220 lead->set_name("Lead");
1221 lead->set_temporary(true);
1224 set<Track *> tracks;
1225 for(BlockList::iterator i=blocks.begin(); i!=blocks.end(); ++i)
1227 const set<Track *> &btracks = (*i)->get_tracks();
1228 for(set<Track *>::const_iterator j=btracks.begin(); j!=btracks.end(); ++j)
1229 if(!target || !target->has_track(**j))
1233 lead->add_tracks(tracks);
1238 bool Train::is_valid_diversion(const Route &diversion, const TrackIter &from)
1240 float diversion_len = 0;
1241 TrackLoopIter track1 = from;
1242 while(diversion.has_track(*track1))
1244 unsigned path = diversion.get_path(*track1);
1245 diversion_len += track1->get_type().get_path_length(path);
1247 track1 = track1.next(path);
1249 if(!track1 || track1.looped())
1253 list<RouteRef>::iterator route = routes.begin();
1254 if(!advance_route(route, *from))
1257 float route_len = 0;
1258 TrackLoopIter track2 = from;
1261 unsigned path = route->route->get_path(*track2);
1262 route_len += track2->get_type().get_path_length(path);
1264 bool ok = (track2!=from && diversion.has_track(*track2));
1266 track2 = track2.next(path);
1276 if(!advance_route(route, *track2))
1280 // Must end up at the same place through both routes
1284 return diversion_len<route_len*1.2;
1288 Train::RouteRef::RouteRef(const Route *r, unsigned d):
1294 Train::Loader::Loader(Train &t):
1295 DataFile::BasicLoader<Train>(t),
1299 add("block", &Loader::block);
1300 add("block_hint", &Loader::block_hint);
1301 add("name", &Loader::name);
1302 add("priority", &Train::priority);
1303 add("quantized_speed", &Loader::quantized_speed);
1304 add("route", &Loader::route);
1305 add("timetable", &Loader::timetable);
1306 add("vehicle", &Loader::vehicle);
1309 void Train::Loader::finish()
1311 if(!obj.blocks.empty())
1313 TrackIter track = obj.blocks.front().track_iter();
1314 float offset = 2*obj.layout.get_catalogue().get_scale();
1315 obj.vehicles.back()->place(*track, track.entry(), offset, Vehicle::BACK_BUFFER);
1317 obj.set_status("Stopped");
1321 void Train::Loader::block(unsigned id)
1329 blk = &obj.layout.get_block(id);
1331 catch(const KeyError &)
1333 blocks_valid = false;
1339 entry = blk->get_endpoint_by_link(*prev_block);
1344 obj.blocks.push_back(BlockIter(blk, entry));
1346 if(blk->get_sensor_id())
1347 obj.layout.get_driver().set_sensor(blk->get_sensor_id(), true);
1352 void Train::Loader::block_hint(unsigned id)
1356 prev_block = &obj.layout.get_block(id);
1358 catch(const KeyError &)
1360 blocks_valid = false;
1364 void Train::Loader::name(const string &n)
1369 void Train::Loader::quantized_speed()
1371 if(obj.speed_quantizer)
1372 load_sub(*obj.speed_quantizer);
1375 void Train::Loader::route(const string &n)
1377 obj.set_route(&obj.layout.get_route(n));
1380 void Train::Loader::timetable()
1383 throw InvalidState("A timetable has already been loaded");
1385 obj.timetable = new Timetable(obj);
1386 load_sub(*obj.timetable);
1389 void Train::Loader::vehicle(ArticleNumber art_nr)
1391 const VehicleType &vtype = obj.layout.get_catalogue().get_vehicle(art_nr);
1392 Vehicle *veh = new Vehicle(obj.layout, vtype);
1393 obj.vehicles.back()->attach_back(*veh);
1394 obj.vehicles.push_back(veh);