3 This file is part of R²C²
4 Copyright © 2006-2011 Mikkosoft Productions, Mikko Rasa
5 Distributed under the GPL
10 #include <msp/strings/formatter.h>
11 #include <msp/time/units.h>
12 #include <msp/time/utils.h>
13 #include "aicontrol.h"
14 #include "catalogue.h"
18 #include "simplecontroller.h"
19 #include "speedquantizer.h"
20 #include "timetable.h"
21 #include "trackiter.h"
22 #include "tracktype.h"
25 #include "vehicletype.h"
37 SetFlag(bool &f): flag(f) { flag = true; }
38 ~SetFlag() { flag = false; }
46 Train::Train(Layout &l, const VehicleType &t, unsigned a, const string &p):
54 cur_blocks_end(blocks.end()),
55 clear_blocks_end(blocks.end()),
59 controller(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));
104 for(vector<Vehicle *>::iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
106 layout.remove_train(*this);
109 void Train::set_name(const string &n)
113 signal_name_changed.emit(name);
116 void Train::set_priority(int p)
121 void Train::yield_to(const Train &t)
126 void Train::add_vehicle(const VehicleType &vt)
128 Vehicle *veh = new Vehicle(layout, vt);
129 vehicles.back()->attach_back(*veh);
130 vehicles.push_back(veh);
133 void Train::remove_vehicle(unsigned i)
135 if(i>=vehicles.size())
136 throw InvalidParameterValue("Vehicle index out of range");
138 throw InvalidParameterValue("Can't remove the locomotive");
140 vehicles.erase(vehicles.begin()+i);
141 if(i<vehicles.size())
142 vehicles[i-1]->attach_back(*vehicles[i]);
145 unsigned Train::get_n_vehicles() const
147 return vehicles.size();
150 Vehicle &Train::get_vehicle(unsigned i)
152 if(i>=vehicles.size())
153 throw InvalidParameterValue("Vehicle index out of range");
157 const Vehicle &Train::get_vehicle(unsigned i) const
159 if(i>=vehicles.size())
160 throw InvalidParameterValue("Vehicle index out of range");
164 void Train::set_control(const string &n, float v)
166 controller->set_control(n, v);
169 void Train::set_active(bool a)
173 if(!a && controller->get_speed())
174 throw InvalidState("Can't deactivate while moving");
179 stop_timeout = Time::TimeStamp();
184 stop_timeout = Time::now()+2*Time::sec;
185 set_status("Stopped");
189 void Train::set_function(unsigned func, bool state)
191 if(!loco_type.get_functions().count(func))
192 throw InvalidParameterValue("Invalid function");
193 layout.get_driver().set_loco_function(address, func, state);
196 float Train::get_control(const string &ctrl) const
198 return controller->get_control(ctrl).value;
201 float Train::get_speed() const
203 return controller->get_speed();
206 bool Train::get_function(unsigned func) const
208 return (functions>>func)&1;
211 void Train::add_ai(TrainAI &ai)
214 ai.signal_event.connect(sigc::bind<0>(signal_ai_event, sigc::ref(ai)));
217 void Train::remove_ai(TrainAI &ai)
219 list<TrainAI *>::iterator i = find(ais.begin(), ais.end(), &ai);
224 TrainAI *Train::get_tagged_ai(const string &tag)
226 for(list<TrainAI *>::iterator i=ais.begin(); i!=ais.end(); ++i)
227 if((*i)->get_tag()==tag)
233 void Train::ai_message(const TrainAI::Message &msg)
235 for(list<TrainAI *>::iterator i=ais.begin(); i!=ais.end(); ++i)
239 bool Train::set_route(const Route *r)
241 free_noncritical_blocks();
244 if(r && !blocks.empty())
246 TrackIter first = blocks.front().track_iter();
247 TrackIter next = blocks.back().next().track_iter();
248 if(!r->has_track(*next))
250 lead = Route::find(next, *r);
253 create_lead_route(lead, lead);
254 routes.push_front(lead);
256 else if(!r->has_track(*first))
257 lead = create_lead_route(0, r);
262 routes.push_back(lead);
265 end_of_route = false;
269 signal_route_changed.emit(get_route());
274 bool Train::go_to(Track &to)
276 for(BlockList::const_iterator i=blocks.begin(); i!=cur_blocks_end; ++i)
277 if((*i)->has_track(to))
279 signal_arrived.emit();
283 free_noncritical_blocks();
285 TrackIter next = blocks.back().next().track_iter();
287 Route *route = Route::find(next, to);
290 create_lead_route(route, route);
291 return set_route(route);
294 bool Train::go_to(const Zone &to)
297 for(BlockList::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
298 tracks.insert((*i)->get_tracks().begin(), (*i)->get_tracks().end());
300 const Zone::TrackSet &ztracks = to.get_tracks();
301 unsigned union_size = 0;
302 for(Zone::TrackSet::const_iterator i=ztracks.begin(); i!=ztracks.end(); ++i)
303 union_size += tracks.count(*i);
305 if(union_size==tracks.size() || union_size==ztracks.size())
307 signal_arrived.emit();
311 free_noncritical_blocks();
313 TrackIter next = blocks.back().next().track_iter();
315 Route *route = Route::find(next, to);
318 create_lead_route(route, route);
319 route->add_tracks(ztracks);
320 return set_route(route);
323 bool Train::divert(Track &from)
325 if(!from.get_turnout_id())
326 throw InvalidParameterValue("Can't divert from a non-turnout");
332 list<RouteRef>::iterator route = routes.begin();
334 // Follow our routes to find out where we're entering the turnout
335 for(TrackLoopIter track = blocks.front().track_iter();;)
337 if(!advance_route(route, *track))
342 Block &block = track->get_block();
343 if(block.get_train()==this && !free_block(block))
346 int route_path = route->route->get_turnout(from.get_turnout_id());
348 // Check that more than one path is available
349 unsigned ep_paths = track.endpoint().paths;
350 if(!(ep_paths&(ep_paths-1)))
353 // Choose some other path
354 for(int i=0; ep_paths>>i; ++i)
355 if((ep_paths&(1<<i)) && i!=route_path)
361 entry = track.entry();
365 track = track.next(route->route->get_path(*track));
367 if(!track || track.looped())
371 TrackIter track = TrackIter(&from, entry).next(path);
376 for(list<RouteRef>::iterator i=routes.begin(); i!=routes.end(); ++i)
377 tracks.insert(i->route->get_tracks().begin(), i->route->get_tracks().end());
378 RefPtr<Route> diversion = Route::find(track, tracks);
382 diversion->set_name("Diversion");
383 diversion->add_track(from);
384 diversion->set_turnout(from.get_turnout_id(), path);
386 if(!is_valid_diversion(*diversion, TrackIter(&from, entry)))
389 // Follow the diversion route until we get back to the original route
390 list<RouteRef>::iterator end = routes.end();
393 for(list<RouteRef>::iterator i=route; (end==routes.end() && i!=routes.end()); ++i)
394 if(i->route->has_track(*track))
397 if(end!=routes.end())
399 else if(!diversion->has_track(*track))
400 throw LogicError("Pathfinder returned a bad route");
402 track = track.next(diversion->get_path(*track));
406 // We are rejoining the same route we diverted from, duplicate it
407 routes.insert(end, *route);
411 routes.erase(route, end);
413 routes.insert(end, RouteRef(diversion.release(), from.get_turnout_id()));
418 const Route *Train::get_route() const
422 return routes.front().route;
425 void Train::place(Block &block, unsigned entry)
427 if(controller->get_speed())
428 throw InvalidState("Must be stopped before placing");
433 accurate_position = false;
435 if(!block.reserve(this))
437 set_status("Unplaced");
441 blocks.push_back(BlockIter(&block, entry));
444 TrackIter track = BlockIter(&block, entry).reverse().track_iter();
445 vehicles.front()->place(*track, track.entry(), 0, Vehicle::FRONT_BUFFER);
449 const Block::Endpoint &bep = block.get_endpoint(entry);
450 vehicles.back()->place(*bep.track, bep.track_ep, 0, Vehicle::BACK_BUFFER);
454 void Train::unplace()
456 if(controller->get_speed())
457 throw InvalidState("Must be stopped before unplacing");
462 accurate_position = false;
464 for(vector<Vehicle *>::iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
467 set_status("Unplaced");
470 bool Train::free_block(Block &block)
472 if(get_reserved_distance_until(&block, false)<controller->get_braking_distance()*1.3)
476 for(BlockList::iterator i=cur_blocks_end; i!=blocks.end(); ++i)
478 if(i->block()==&block)
482 release_blocks(i, blocks.end());
485 else if((*i)->get_sensor_id())
492 void Train::free_noncritical_blocks()
497 if(controller->get_speed()==0)
499 release_blocks(cur_blocks_end, blocks.end());
503 float margin = 10*layout.get_catalogue().get_scale();
504 float min_dist = controller->get_braking_distance()*1.3+margin;
506 Vehicle &veh = *(reverse ? vehicles.back() : vehicles.front());
508 TrackIter track(veh.get_track(), veh.get_entry());
509 BlockList::iterator block = blocks.begin();
511 while(block!=blocks.end() && !(*block)->has_track(*track))
514 if(block==cur_blocks_end)
518 float dist = veh.get_offset();
522 dist = track->get_type().get_path_length(track->get_active_path())-dist;
523 dist -= veh.get_type().get_length()/2;
528 track = track.next();
530 if(!(*block)->has_track(*track))
533 if(block==cur_blocks_end)
535 if(block==blocks.end())
538 if(dist>min_dist && nsens>0)
540 release_blocks(block, blocks.end());
544 if(in_rsv && (*block)->get_sensor_id())
548 dist += track->get_type().get_path_length(track->get_active_path());
552 int Train::get_entry_to_block(Block &block) const
554 for(BlockList::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
555 if(i->block()==&block)
560 float Train::get_reserved_distance() const
566 TrackIter next = blocks.back().next().track_iter();
567 if(next && next->get_type().is_turnout())
568 margin = 15*layout.get_catalogue().get_scale();
570 return max(get_reserved_distance_until(0, false)-margin, 0.0f);
573 void Train::tick(const Time::TimeStamp &t, const Time::TimeDelta &dt)
575 if(!active && stop_timeout && t>=stop_timeout)
577 release_blocks(cur_blocks_end, blocks.end());
578 stop_timeout = Time::TimeStamp();
581 Driver &driver = layout.get_driver();
583 for(list<TrainAI *>::iterator i=ais.begin(); i!=ais.end(); ++i)
585 controller->tick(dt);
586 float speed = controller->get_speed();
588 if(controller->get_reverse()!=reverse)
590 reverse = controller->get_reverse();
591 driver.set_loco_reverse(address, reverse);
593 release_blocks(cur_blocks_end, blocks.end());
594 reverse_blocks(blocks);
601 unsigned speed_step = speed_quantizer->find_speed_step(speed);
602 if(speed_step!=current_speed_step && !speed_changing && !driver.is_halted() && driver.get_power())
604 speed_changing = true;
605 driver.set_loco_speed(address, speed_step);
610 set_status(format("Traveling %d kmh", get_travel_speed()));
612 set_status("Waiting");
615 speed = speed_quantizer->get_speed(current_speed_step);
623 Vehicle &vehicle = *(reverse ? vehicles.back() : vehicles.front());
624 Track *track = vehicle.get_track();
627 for(BlockList::const_iterator i=blocks.begin(); (!ok && i!=cur_blocks_end); ++i)
628 ok = (*i)->has_track(*track);
630 float d = speed*(dt/Time::sec);
633 SetFlag setf(advancing);
634 vehicle.advance(reverse ? -d : d);
636 else if(accurate_position)
639 if(overshoot_dist>40*layout.get_catalogue().get_scale())
641 layout.emergency(name+" has not arrived at sensor");
642 accurate_position = false;
646 else if(end_of_route && cur_blocks_end==blocks.end())
649 signal_arrived.emit();
653 if(!blocks.empty() && !blocks.front()->get_sensor_id())
655 float dist = get_reserved_distance_until(&*blocks.front(), true);
657 if(dist>10*layout.get_catalogue().get_scale())
659 blocks.front()->reserve(0);
665 void Train::save(list<DataFile::Statement> &st) const
667 st.push_back((DataFile::Statement("name"), name));
669 st.push_back((DataFile::Statement("priority"), priority));
671 for(vector<Vehicle *>::const_iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
672 if(i!=vehicles.begin())
673 st.push_back((DataFile::Statement("vehicle"), (*i)->get_type().get_article_number()));
677 DataFile::Statement ss("quantized_speed");
678 speed_quantizer->save(ss.sub);
682 if(!blocks.empty() && cur_blocks_end!=blocks.begin())
684 BlockList blks(blocks.begin(), BlockList::const_iterator(cur_blocks_end));
686 reverse_blocks(blks);
688 BlockIter prev = blks.front().flip();
689 st.push_back((DataFile::Statement("block_hint"), prev->get_id()));
691 for(BlockList::const_iterator i=blks.begin(); i!=blks.end(); ++i)
692 st.push_back((DataFile::Statement("block"), (*i)->get_id()));
697 list<RouteRef>::const_iterator i = routes.begin();
698 for(; (i!=routes.end() && i->route->is_temporary()); ++i) ;
700 st.push_back((DataFile::Statement("route"), i->route->get_name()));
703 // XXX Need more generic way of saving AI state
704 for(list<TrainAI *>::const_iterator i=ais.begin(); i!=ais.end(); ++i)
705 if(Timetable *timetable = dynamic_cast<Timetable *>(*i))
707 DataFile::Statement ss("timetable");
708 timetable->save(ss.sub);
713 void Train::control_changed(const Controller::Control &ctrl)
715 signal_control_changed.emit(ctrl.name, ctrl.value);
718 void Train::loco_speed_event(unsigned addr, unsigned speed, bool rev)
722 current_speed_step = speed;
724 layout.get_driver().set_loco_reverse(address, reverse);
725 speed_changing = false;
730 void Train::loco_func_event(unsigned addr, unsigned func, bool state)
735 functions |= 1<<func;
737 functions &= ~(1<<func);
739 signal_function_changed.emit(func, state);
743 void Train::sensor_event(unsigned addr, bool state)
747 // Find the first sensor block from our reserved blocks that isn't this sensor
748 BlockList::iterator end;
750 for(end=cur_blocks_end; end!=blocks.end(); ++end)
751 if((*end)->get_sensor_id())
753 if((*end)->get_sensor_id()!=addr)
768 // Compute speed and update related state
769 float travel_time_secs = (Time::now()-last_entry_time)/Time::sec;
773 if(speed_quantizer && current_speed_step>0)
774 speed_quantizer->learn(current_speed_step, travel_dist/travel_time_secs, travel_time_secs);
775 set_status(format("Traveling %d kmh", get_travel_speed()));
779 for(BlockList::iterator j=cur_blocks_end; j!=end; ++j)
781 travel_dist += (*j)->get_path_length(j->entry());
783 if((*j)->get_sensor_id()==addr && !advancing)
785 TrackIter track = j->track_iter();
788 track = track.flip();
789 vehicles.back()->place(*track, track.entry(), 0, Vehicle::BACK_AXLE);
792 vehicles.front()->place(*track, track.entry(), 0, Vehicle::FRONT_AXLE);
795 last_entry_time = Time::now();
797 accurate_position = true;
800 // Check if we've reached the next route
803 const Route &route = *(++routes.begin())->route;
804 for(BlockList::iterator j=cur_blocks_end; j!=end; ++j)
805 if(route.has_track(*j->track_iter()))
809 signal_route_changed.emit(routes.front().route);
814 // Move blocks up to the next sensor to our current blocks
815 for(BlockList::iterator j=cur_blocks_end; j!=end; ++j)
816 signal_advanced.emit(**j);
817 cur_blocks_end = end;
819 // Try to get more blocks if we're moving
824 layout.emergency("Sensor for "+name+" triggered out of order");
828 const Vehicle &veh = *(reverse ? vehicles.front() : vehicles.back());
830 // Find the first sensor in our current blocks that's still active
831 BlockList::iterator end = blocks.begin();
832 for(BlockList::iterator i=blocks.begin(); i!=cur_blocks_end; ++i)
834 if((*i)->has_track(*veh.get_track()))
836 if((*i)->get_sensor_id())
838 if(layout.get_driver().get_sensor((*i)->get_sensor_id()))
848 if(end!=blocks.begin() && end!=cur_blocks_end)
849 // Free blocks up to the last inactive sensor
850 release_blocks(blocks.begin(), end);
854 void Train::turnout_path_changed(Track &track)
856 for(list<BlockIter>::iterator i=blocks.begin(); i!=blocks.end(); ++i)
857 if((*i)->get_turnout_id()==track.get_turnout_id() && !reserving)
858 check_turnout_paths(false);
861 void Train::halt_event(bool h)
864 accurate_position = false;
867 void Train::block_reserved(const Block &block, const Train *train)
869 if(&block==pending_block && !train && !reserving)
873 void Train::reserve_more()
875 if(!active || blocks.empty() || end_of_route)
878 BlockIter start = blocks.back();
883 // See how many sensor blocks and how much track we already have
886 for(BlockList::const_iterator i=cur_blocks_end; i!=blocks.end(); ++i)
888 if((*i)->get_sensor_id())
891 dist += (*i)->get_path_length(i->entry());
894 list<RouteRef>::iterator cur_route = routes.begin();
895 advance_route(cur_route, *start.track_iter());
897 float approach_margin = 50*layout.get_catalogue().get_scale();
898 float min_dist = controller->get_braking_distance()*1.3+approach_margin*2;
900 BlockIter block = start;
901 list<BlockIter>::iterator good_end = blocks.end();
902 Track *divert_track = 0;
903 bool try_divert = false;
904 Train *blocking_train = 0;
905 BlockList contested_blocks;
907 SetFlag setf(reserving);
911 BlockIter last = block;
912 block = block.next(cur_route!=routes.end() ? cur_route->route : 0);
913 if(!block || block->get_endpoints().size()<2)
917 good_end = blocks.end();
923 TrackIter track = block.track_iter();
925 if(cur_route!=routes.end())
927 if(!advance_route(cur_route, *track))
929 // Keep the blocks if we arrived at the end of the route
932 good_end = blocks.end();
939 if(block->get_turnout_id() && !last->get_turnout_id())
941 /* We can keep the blocks if we arrive at a turnout from a non-turnout
942 block. Having a turnout block as our last reserved block is not good
943 as it would limit our diversion possibilities for little benefit. */
944 good_end = blocks.end();
945 if(nsens>=3 && dist>=min_dist)
951 if(block->get_train()!=blocking_train)
953 if(blocking_train->free_block(*contested_blocks.back()))
955 // Roll back and start actually reserving the blocks
956 block = blocks.back();
957 cur_route = routes.begin();
958 advance_route(cur_route, *block.track_iter().track());
959 if(blocking_train->get_priority()==priority)
960 blocking_train->yield_to(*this);
966 yield_to(*blocking_train);
967 pending_block = contested_blocks.front().block();
968 try_divert = divert_track;
974 contested_blocks.push_back(block);
979 bool reserved = block->reserve(this);
982 /* We've found another train. If it wants to exit the block from the
983 same endpoint we're trying to enter from or the other way around,
984 treat it as coming towards us. Otherwise treat it as going in the
986 Train *other_train = block->get_train();
987 int other_entry = other_train->get_entry_to_block(*block);
989 throw LogicError("Block reservation inconsistency");
991 unsigned exit = block.reverse().entry();
992 unsigned other_exit = BlockIter(block.block(), other_entry).reverse().entry();
993 bool entry_conflict = (block.entry()==other_exit);
994 bool exit_conflict = (exit==static_cast<unsigned>(other_entry));
995 if(!entry_conflict && !last->get_turnout_id())
997 /* The other train is not coming to the blocks we're holding, so we
999 good_end = blocks.end();
1001 if(static_cast<unsigned>(other_entry)==block.entry())
1002 preceding_train = other_train;
1005 int other_prio = other_train->get_priority();
1007 if(!entry_conflict && !exit_conflict && other_prio<priority)
1009 /* Ask a lesser priority train going to the same direction to free
1011 if(other_train->free_block(*block))
1012 reserved = block->reserve(this);
1014 else if(other_train!=yielding_to && (other_prio<priority || (other_prio==priority && entry_conflict)))
1016 /* A lesser priority train is coming at us, we must ask it to free
1017 enough blocks to get clear of it to avoid a potential deadlock */
1018 blocking_train = other_train;
1019 contested_blocks.clear();
1020 contested_blocks.push_back(block);
1023 else if(divert_track && (entry_conflict || exit_conflict || !other_train->is_active()))
1024 // We are blocked, but there's a diversion possibility
1029 pending_block = &*block;
1034 if(block->get_turnout_id())
1036 const TrackType::Endpoint &track_ep = track.endpoint();
1037 bool multiple_paths = (track_ep.paths&(track_ep.paths-1));
1039 if(multiple_paths && cur_route!=routes.end() && cur_route->diversion!=block->get_turnout_id())
1040 /* There's multiple paths to be taken and we are on a route - take
1041 note of the diversion possibility */
1042 divert_track = &*track;
1045 if(!contested_blocks.empty() && contested_blocks.front()==block)
1046 contested_blocks.pop_front();
1048 blocks.push_back(block);
1050 if(cur_blocks_end==blocks.end())
1052 if(clear_blocks_end==blocks.end())
1054 if(good_end==blocks.end())
1057 if(block->get_sensor_id())
1060 dist += block->get_path_length(block.entry());
1063 // Unreserve blocks that were not good
1064 release_blocks(good_end, blocks.end());
1066 if(blocks.back()!=start)
1067 // We got some new blocks, so no longer need to yield
1070 check_turnout_paths(true);
1072 // Make any sensorless blocks at the beginning immediately current
1073 while(cur_blocks_end!=clear_blocks_end && !(*cur_blocks_end)->get_sensor_id())
1076 if(try_divert && divert(*divert_track))
1080 void Train::check_turnout_paths(bool set)
1082 if(clear_blocks_end==blocks.end())
1085 for(list<BlockIter>::iterator i=clear_blocks_end; i!=blocks.end(); ++i)
1087 if((*i)->get_turnout_id())
1089 TrackIter track = i->track_iter();
1090 const TrackType::Endpoint &track_ep = track.endpoint();
1093 list<BlockIter>::iterator j = i;
1094 if(++j!=blocks.end())
1096 TrackIter rev = j->track_iter().flip();
1097 unsigned mask = rev.endpoint().paths&track_ep.paths;
1098 for(path=0; mask>1; mask>>=1, ++path) ;
1103 if(path!=track->get_active_path())
1106 track->set_active_path(path);
1108 /* Check again, in case the driver was able to service the request
1110 if(!set || path!=track->get_active_path())
1115 if(i==clear_blocks_end)
1120 float Train::get_reserved_distance_until(const Block *until_block, bool back) const
1125 Vehicle &veh = *(reverse!=back ? vehicles.back() : vehicles.front());
1126 const VehicleType &vtype = veh.get_type();
1128 TrackIter track(veh.get_track(), veh.get_entry());
1129 if(!track) // XXX Probably unnecessary
1132 BlockList::const_iterator block = blocks.begin();
1133 while(block!=clear_blocks_end && !(*block)->has_track(*track))
1135 if(block==clear_blocks_end || &**block==until_block)
1138 float result = veh.get_offset();
1140 track = track.reverse();
1142 result = track->get_type().get_path_length(track->get_active_path())-result;
1143 result -= vtype.get_length()/2;
1147 track = track.next();
1151 if(!(*block)->has_track(*track))
1155 if(block==blocks.begin())
1162 if(block==clear_blocks_end)
1166 if(&**block==until_block)
1170 result += track->get_type().get_path_length(track->get_active_path());
1176 float Train::get_travel_speed() const
1180 speed = speed_quantizer->get_speed(current_speed_step);
1182 speed = controller->get_speed();
1183 float scale = layout.get_catalogue().get_scale();
1184 return static_cast<int>(round(speed/scale*3.6/5))*5;
1187 void Train::set_status(const string &s)
1190 signal_status_changed.emit(s);
1193 void Train::release_blocks()
1195 release_blocks(blocks.begin(), blocks.end());
1198 void Train::release_blocks(BlockList::iterator begin, BlockList::iterator end)
1202 if(begin==cur_blocks_end)
1203 cur_blocks_end = end;
1204 if(begin==clear_blocks_end)
1205 clear_blocks_end = end;
1207 Block &block = **begin;
1208 blocks.erase(begin++);
1211 if(begin==blocks.end())
1212 end_of_route = false;
1216 void Train::reverse_blocks(BlockList &blks) const
1219 for(BlockList::iterator i=blks.begin(); i!=blks.end(); ++i)
1223 bool Train::advance_route(list<RouteRef>::iterator &iter, Track &track)
1225 while(iter!=routes.end() && !iter->route->has_track(track))
1227 if(iter==routes.end())
1230 list<RouteRef>::iterator next = iter;
1232 if(next!=routes.end() && next->diversion && next->route->has_track(track))
1238 Route *Train::create_lead_route(Route *lead, const Route *target)
1242 lead = new Route(layout);
1243 lead->set_name("Lead");
1244 lead->set_temporary(true);
1247 set<Track *> tracks;
1248 for(BlockList::iterator i=blocks.begin(); i!=blocks.end(); ++i)
1250 const set<Track *> &btracks = (*i)->get_tracks();
1251 for(set<Track *>::const_iterator j=btracks.begin(); j!=btracks.end(); ++j)
1252 if(!target || !target->has_track(**j))
1256 lead->add_tracks(tracks);
1261 bool Train::is_valid_diversion(const Route &diversion, const TrackIter &from)
1263 float diversion_len = 0;
1264 TrackLoopIter track1 = from;
1265 while(diversion.has_track(*track1))
1267 unsigned path = diversion.get_path(*track1);
1268 diversion_len += track1->get_type().get_path_length(path);
1270 track1 = track1.next(path);
1272 if(!track1 || track1.looped())
1276 list<RouteRef>::iterator route = routes.begin();
1277 if(!advance_route(route, *from))
1280 float route_len = 0;
1281 TrackLoopIter track2 = from;
1284 unsigned path = route->route->get_path(*track2);
1285 route_len += track2->get_type().get_path_length(path);
1287 bool ok = (track2!=from && diversion.has_track(*track2));
1289 track2 = track2.next(path);
1299 if(!advance_route(route, *track2))
1303 // Must end up at the same place through both routes
1307 return diversion_len<route_len*1.2;
1311 Train::RouteRef::RouteRef(const Route *r, unsigned d):
1317 Train::Loader::Loader(Train &t):
1318 DataFile::BasicLoader<Train>(t),
1322 add("block", &Loader::block);
1323 add("block_hint", &Loader::block_hint);
1324 add("name", &Loader::name);
1325 add("priority", &Train::priority);
1326 add("quantized_speed", &Loader::quantized_speed);
1327 add("route", &Loader::route);
1328 add("timetable", &Loader::timetable);
1329 add("vehicle", &Loader::vehicle);
1332 void Train::Loader::finish()
1334 if(!obj.blocks.empty())
1336 TrackIter track = obj.blocks.front().track_iter();
1337 float offset = 2*obj.layout.get_catalogue().get_scale();
1338 obj.vehicles.back()->place(*track, track.entry(), offset, Vehicle::BACK_BUFFER);
1340 obj.set_status("Stopped");
1344 void Train::Loader::block(unsigned id)
1352 blk = &obj.layout.get_block(id);
1354 catch(const KeyError &)
1356 blocks_valid = false;
1362 entry = blk->get_endpoint_by_link(*prev_block);
1367 obj.blocks.push_back(BlockIter(blk, entry));
1369 if(blk->get_sensor_id())
1370 obj.layout.get_driver().set_sensor(blk->get_sensor_id(), true);
1375 void Train::Loader::block_hint(unsigned id)
1379 prev_block = &obj.layout.get_block(id);
1381 catch(const KeyError &)
1383 blocks_valid = false;
1387 void Train::Loader::name(const string &n)
1392 void Train::Loader::quantized_speed()
1394 if(obj.speed_quantizer)
1395 load_sub(*obj.speed_quantizer);
1398 void Train::Loader::route(const string &n)
1400 obj.set_route(&obj.layout.get_route(n));
1403 void Train::Loader::timetable()
1405 Timetable *ttbl = new Timetable(obj);
1409 void Train::Loader::vehicle(ArticleNumber art_nr)
1411 const VehicleType &vtype = obj.layout.get_catalogue().get_vehicle(art_nr);
1412 Vehicle *veh = new Vehicle(obj.layout, vtype);
1413 obj.vehicles.back()->attach_back(*veh);
1414 obj.vehicles.push_back(veh);