3 This file is part of R²C²
4 Copyright © 2006-2010 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 "timetable.h"
19 #include "trackiter.h"
20 #include "tracktype.h"
23 #include "vehicletype.h"
35 SetFlag(bool &f): flag(f) { flag = true; }
36 ~SetFlag() { flag = false; }
44 Train::Train(Layout &l, const VehicleType &t, unsigned a, const string &p):
52 cur_blocks_end(blocks.end()),
53 clear_blocks_end(blocks.end()),
57 controller(new AIControl(*this, new SimpleController)),
60 current_speed_step(0),
61 speed_changing(false),
68 real_speed(layout.get_driver().get_protocol_speed_steps(protocol)+1),
69 accurate_position(false),
72 if(!loco_type.is_locomotive())
73 throw InvalidParameterValue("Initial vehicle must be a locomotive");
75 vehicles.push_back(new Vehicle(layout, loco_type));
77 layout.add_train(*this);
79 layout.get_driver().add_loco(address, protocol);
80 layout.get_driver().signal_loco_speed.connect(sigc::mem_fun(this, &Train::loco_speed_event));
81 layout.get_driver().signal_loco_function.connect(sigc::mem_fun(this, &Train::loco_func_event));
83 layout.signal_block_reserved.connect(sigc::mem_fun(this, &Train::block_reserved));
84 layout.get_driver().signal_sensor.connect(sigc::mem_fun(this, &Train::sensor_event));
86 layout.get_driver().signal_halt.connect(sigc::mem_fun(this, &Train::halt_event));
88 const set<Track *> &tracks = layout.get_tracks();
89 for(set<Track *>::const_iterator i=tracks.begin(); i!=tracks.end(); ++i)
90 if((*i)->get_turnout_id())
91 (*i)->signal_path_changed.connect(sigc::hide(sigc::bind(sigc::mem_fun(this, &Train::turnout_path_changed), sigc::ref(**i))));
93 controller->signal_control_changed.connect(sigc::mem_fun(this, &Train::control_changed));
100 for(vector<Vehicle *>::iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
102 layout.remove_train(*this);
105 void Train::set_name(const string &n)
109 signal_name_changed.emit(name);
112 void Train::set_priority(int p)
117 void Train::yield_to(const Train &t)
122 void Train::add_vehicle(const VehicleType &vt)
124 Vehicle *veh = new Vehicle(layout, vt);
125 vehicles.back()->attach_back(*veh);
126 vehicles.push_back(veh);
129 void Train::remove_vehicle(unsigned i)
131 if(i>=vehicles.size())
132 throw InvalidParameterValue("Vehicle index out of range");
134 throw InvalidParameterValue("Can't remove the locomotive");
136 vehicles.erase(vehicles.begin()+i);
137 if(i<vehicles.size())
138 vehicles[i-1]->attach_back(*vehicles[i]);
141 unsigned Train::get_n_vehicles() const
143 return vehicles.size();
146 Vehicle &Train::get_vehicle(unsigned i)
148 if(i>=vehicles.size())
149 throw InvalidParameterValue("Vehicle index out of range");
153 const Vehicle &Train::get_vehicle(unsigned i) const
155 if(i>=vehicles.size())
156 throw InvalidParameterValue("Vehicle index out of range");
160 void Train::set_control(const string &n, float v)
162 controller->set_control(n, v);
165 void Train::set_active(bool a)
169 if(!a && controller->get_speed())
170 throw InvalidState("Can't deactivate while moving");
175 stop_timeout = Time::TimeStamp();
180 stop_timeout = Time::now()+2*Time::sec;
181 set_status("Stopped");
185 void Train::set_function(unsigned func, bool state)
187 if(!loco_type.get_functions().count(func))
188 throw InvalidParameterValue("Invalid function");
190 layout.get_driver().set_loco_function(address, func, state);
192 layout.get_driver().set_loco_function(address+1, func-4, state);
195 float Train::get_control(const string &ctrl) const
197 return controller->get_control(ctrl).value;
200 float Train::get_speed() const
202 return controller->get_speed();
205 bool Train::get_function(unsigned func) const
207 return (functions>>func)&1;
210 void Train::set_timetable(Timetable *tt)
216 bool Train::set_route(const Route *r)
218 free_noncritical_blocks();
221 if(r && !blocks.empty())
223 TrackIter first = blocks.front().track_iter();
224 TrackIter next = blocks.back().next().track_iter();
225 if(!r->has_track(*next))
227 lead = Route::find(next, *r);
230 create_lead_route(lead, lead);
231 routes.push_front(lead);
233 else if(!r->has_track(*first))
234 lead = create_lead_route(0, r);
239 routes.push_back(lead);
242 end_of_route = false;
246 signal_route_changed.emit(get_route());
251 bool Train::go_to(Track &to)
253 for(BlockList::const_iterator i=blocks.begin(); i!=cur_blocks_end; ++i)
254 if((*i)->has_track(to))
256 signal_arrived.emit();
260 free_noncritical_blocks();
262 TrackIter next = blocks.back().next().track_iter();
264 Route *route = Route::find(next, to);
267 create_lead_route(route, route);
268 return set_route(route);
271 bool Train::go_to(const Zone &to)
274 for(BlockList::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
275 tracks.insert((*i)->get_tracks().begin(), (*i)->get_tracks().end());
277 const Zone::TrackSet &ztracks = to.get_tracks();
278 unsigned union_size = 0;
279 for(Zone::TrackSet::const_iterator i=ztracks.begin(); i!=ztracks.end(); ++i)
280 union_size += tracks.count(*i);
282 if(union_size==tracks.size() || union_size==ztracks.size())
284 signal_arrived.emit();
288 free_noncritical_blocks();
290 TrackIter next = blocks.back().next().track_iter();
292 Route *route = Route::find(next, to);
295 create_lead_route(route, route);
296 route->add_tracks(ztracks);
297 return set_route(route);
300 bool Train::divert(Track &from)
302 if(!from.get_turnout_id())
303 throw InvalidParameterValue("Can't divert from a non-turnout");
309 list<RouteRef>::iterator route = routes.begin();
311 // Follow our routes to find out where we're entering the turnout
312 for(TrackLoopIter track = blocks.front().track_iter();;)
314 if(!advance_route(route, *track))
319 Block &block = track->get_block();
320 if(block.get_train()==this && !free_block(block))
323 int route_path = route->route->get_turnout(from.get_turnout_id());
325 // Check that more than one path is available
326 unsigned ep_paths = track.endpoint().paths;
327 if(!(ep_paths&(ep_paths-1)))
330 // Choose some other path
331 for(int i=0; ep_paths>>i; ++i)
332 if((ep_paths&(1<<i)) && i!=route_path)
338 entry = track.entry();
342 track = track.next(route->route->get_path(*track));
344 if(!track || track.looped())
348 TrackIter track = TrackIter(&from, entry).next(path);
353 for(list<RouteRef>::iterator i=routes.begin(); i!=routes.end(); ++i)
354 tracks.insert(i->route->get_tracks().begin(), i->route->get_tracks().end());
355 RefPtr<Route> diversion = Route::find(track, tracks);
359 diversion->set_name("Diversion");
360 diversion->add_track(from);
361 diversion->set_turnout(from.get_turnout_id(), path);
363 if(!is_valid_diversion(*diversion, TrackIter(&from, entry)))
366 // Follow the diversion route until we get back to the original route
367 list<RouteRef>::iterator end = routes.end();
370 for(list<RouteRef>::iterator i=route; (end==routes.end() && i!=routes.end()); ++i)
371 if(i->route->has_track(*track))
374 if(end!=routes.end())
376 else if(!diversion->has_track(*track))
377 throw LogicError("Pathfinder returned a bad route");
379 track = track.next(diversion->get_path(*track));
383 // We are rejoining the same route we diverted from, duplicate it
384 routes.insert(end, *route);
388 routes.erase(route, end);
390 routes.insert(end, RouteRef(diversion.release(), from.get_turnout_id()));
395 const Route *Train::get_route() const
399 return routes.front().route;
402 void Train::place(Block &block, unsigned entry)
404 if(controller->get_speed())
405 throw InvalidState("Must be stopped before placing");
410 accurate_position = false;
412 if(!block.reserve(this))
414 set_status("Unplaced");
418 blocks.push_back(BlockIter(&block, entry));
421 TrackIter track = BlockIter(&block, entry).reverse().track_iter();
422 vehicles.front()->place(*track, track.entry(), 0, Vehicle::FRONT_BUFFER);
426 const Block::Endpoint &bep = block.get_endpoint(entry);
427 vehicles.back()->place(*bep.track, bep.track_ep, 0, Vehicle::BACK_BUFFER);
431 void Train::unplace()
433 if(controller->get_speed())
434 throw InvalidState("Must be stopped before unplacing");
439 accurate_position = false;
441 for(vector<Vehicle *>::iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
444 set_status("Unplaced");
447 bool Train::free_block(Block &block)
449 float margin = 10*layout.get_catalogue().get_scale();
450 if(get_reserved_distance_until(&block, false)<controller->get_braking_distance()*1.3+margin)
454 for(BlockList::iterator i=cur_blocks_end; i!=blocks.end(); ++i)
456 if(i->block()==&block)
460 release_blocks(i, blocks.end());
463 else if((*i)->get_sensor_id())
470 void Train::free_noncritical_blocks()
475 if(controller->get_speed()==0)
477 release_blocks(cur_blocks_end, blocks.end());
481 float margin = 10*layout.get_catalogue().get_scale();
482 float min_dist = controller->get_braking_distance()*1.3+margin;
484 Vehicle &veh = *(reverse ? vehicles.back() : vehicles.front());
486 TrackIter track(veh.get_track(), veh.get_entry());
487 BlockList::iterator block = blocks.begin();
489 while(block!=blocks.end() && !(*block)->has_track(*track))
492 if(block==cur_blocks_end)
496 float dist = veh.get_offset();
500 dist = track->get_type().get_path_length(track->get_active_path())-dist;
501 dist -= veh.get_type().get_length()/2;
506 track = track.next();
508 if(!(*block)->has_track(*track))
511 if(block==cur_blocks_end)
513 if(block==blocks.end())
516 if(dist>min_dist && nsens>0)
518 release_blocks(block, blocks.end());
522 if(in_rsv && (*block)->get_sensor_id())
526 dist += track->get_type().get_path_length(track->get_active_path());
530 int Train::get_entry_to_block(Block &block) const
532 for(BlockList::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
533 if(i->block()==&block)
538 float Train::get_reserved_distance() const
540 return get_reserved_distance_until(0, false);
543 void Train::tick(const Time::TimeStamp &t, const Time::TimeDelta &dt)
545 if(!active && stop_timeout && t>=stop_timeout)
547 release_blocks(cur_blocks_end, blocks.end());
548 stop_timeout = Time::TimeStamp();
551 Driver &driver = layout.get_driver();
555 controller->tick(dt);
556 float speed = controller->get_speed();
557 unsigned speed_step = find_speed_step(speed);
559 if(controller->get_reverse()!=reverse)
561 reverse = controller->get_reverse();
562 driver.set_loco_reverse(address, reverse);
564 release_blocks(cur_blocks_end, blocks.end());
565 reverse_blocks(blocks);
569 if(speed_step!=current_speed_step && !speed_changing && !driver.is_halted() && driver.get_power())
571 speed_changing = true;
572 driver.set_loco_speed(address, speed_step);
577 set_status(format("Traveling %d kmh", get_travel_speed()));
579 set_status("Waiting");
587 Vehicle &vehicle = *(reverse ? vehicles.back() : vehicles.front());
588 Track *track = vehicle.get_track();
591 for(BlockList::const_iterator i=blocks.begin(); (!ok && i!=cur_blocks_end); ++i)
592 ok = (*i)->has_track(*track);
595 if(real_speed.size()>1)
596 d = get_real_speed(current_speed_step)*(dt/Time::sec);
598 d = speed*(dt/Time::sec);
601 SetFlag setf(advancing);
602 vehicle.advance(reverse ? -d : d);
604 else if(accurate_position)
607 if(overshoot_dist>40*layout.get_catalogue().get_scale())
609 layout.emergency(name+" has not arrived at sensor");
610 accurate_position = false;
614 else if(end_of_route && cur_blocks_end==blocks.end())
617 signal_arrived.emit();
621 if(!blocks.empty() && !blocks.front()->get_sensor_id())
623 float dist = get_reserved_distance_until(&*blocks.front(), true);
625 if(dist>10*layout.get_catalogue().get_scale())
627 blocks.front()->reserve(0);
633 void Train::save(list<DataFile::Statement> &st) const
635 st.push_back((DataFile::Statement("name"), name));
637 st.push_back((DataFile::Statement("priority"), priority));
639 for(vector<Vehicle *>::const_iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
640 if(i!=vehicles.begin())
641 st.push_back((DataFile::Statement("vehicle"), (*i)->get_type().get_article_number()));
643 for(unsigned i=0; i<real_speed.size(); ++i)
644 if(real_speed[i].weight)
645 st.push_back((DataFile::Statement("real_speed"), i, real_speed[i].speed, real_speed[i].weight));
647 if(!blocks.empty() && cur_blocks_end!=blocks.begin())
649 BlockList blks(blocks.begin(), BlockList::const_iterator(cur_blocks_end));
651 reverse_blocks(blks);
653 BlockIter prev = blks.front().flip();
654 st.push_back((DataFile::Statement("block_hint"), prev->get_id()));
656 for(BlockList::const_iterator i=blks.begin(); i!=blks.end(); ++i)
657 st.push_back((DataFile::Statement("block"), (*i)->get_id()));
662 list<RouteRef>::const_iterator i = routes.begin();
663 for(; (i!=routes.end() && i->route->is_temporary()); ++i) ;
665 st.push_back((DataFile::Statement("route"), i->route->get_name()));
670 DataFile::Statement ss("timetable");
671 timetable->save(ss.sub);
676 void Train::control_changed(const Controller::Control &ctrl)
678 signal_control_changed.emit(ctrl.name, ctrl.value);
681 void Train::loco_speed_event(unsigned addr, unsigned speed, bool)
685 current_speed_step = speed;
686 speed_changing = false;
691 void Train::loco_func_event(unsigned addr, unsigned func, bool state)
693 if(addr==address || (addr==address+1 && loco_type.get_max_function()>4))
698 functions |= 1<<func;
700 functions &= ~(1<<func);
702 signal_function_changed.emit(func, state);
706 void Train::sensor_event(unsigned addr, bool state)
710 // Find the first sensor block from our reserved blocks that isn't this sensor
711 BlockList::iterator end;
713 for(end=cur_blocks_end; end!=blocks.end(); ++end)
714 if((*end)->get_sensor_id())
716 if((*end)->get_sensor_id()!=addr)
731 // Compute speed and update related state
732 float travel_time_secs = (Time::now()-last_entry_time)/Time::sec;
736 if(current_speed_step>0)
738 RealSpeed &rs = real_speed[current_speed_step];
739 rs.add(travel_dist/travel_time_secs, travel_time_secs);
741 set_status(format("Traveling %d kmh", get_travel_speed()));
745 for(BlockList::iterator j=cur_blocks_end; j!=end; ++j)
747 travel_dist += (*j)->get_path_length(j->entry());
749 if((*j)->get_sensor_id()==addr && !advancing)
751 TrackIter track = j->track_iter();
754 track = track.flip();
755 vehicles.back()->place(*track, track.entry(), 0, Vehicle::BACK_AXLE);
758 vehicles.front()->place(*track, track.entry(), 0, Vehicle::FRONT_AXLE);
761 last_entry_time = Time::now();
763 accurate_position = true;
766 // Check if we've reached the next route
769 const Route &route = *(++routes.begin())->route;
770 for(BlockList::iterator j=cur_blocks_end; j!=end; ++j)
771 if(route.has_track(*j->track_iter()))
775 signal_route_changed.emit(routes.front().route);
780 // Move blocks up to the next sensor to our current blocks
781 cur_blocks_end = end;
783 // Try to get more blocks if we're moving
788 layout.emergency("Sensor for "+name+" triggered out of order");
792 const Vehicle &veh = *(reverse ? vehicles.front() : vehicles.back());
794 // Find the first sensor in our current blocks that's still active
795 BlockList::iterator end = blocks.begin();
796 for(BlockList::iterator i=blocks.begin(); i!=cur_blocks_end; ++i)
798 if((*i)->has_track(*veh.get_track()))
800 if((*i)->get_sensor_id())
802 if(layout.get_driver().get_sensor((*i)->get_sensor_id()))
812 if(end!=blocks.begin() && end!=cur_blocks_end)
813 // Free blocks up to the last inactive sensor
814 release_blocks(blocks.begin(), end);
818 void Train::turnout_path_changed(Track &track)
820 for(list<BlockIter>::iterator i=blocks.begin(); i!=blocks.end(); ++i)
821 if((*i)->get_turnout_id()==track.get_turnout_id() && !reserving)
822 check_turnout_paths(false);
825 void Train::halt_event(bool h)
828 accurate_position = false;
831 void Train::block_reserved(const Block &block, const Train *train)
833 if(&block==pending_block && !train && !reserving)
837 void Train::reserve_more()
839 if(!active || blocks.empty() || end_of_route)
842 BlockIter start = blocks.back();
847 // See how many sensor blocks and how much track we already have
850 for(BlockList::const_iterator i=cur_blocks_end; i!=blocks.end(); ++i)
852 if((*i)->get_sensor_id())
855 dist += (*i)->get_path_length(i->entry());
858 list<RouteRef>::iterator cur_route = routes.begin();
859 advance_route(cur_route, *start.track_iter());
861 float approach_margin = 50*layout.get_catalogue().get_scale();
862 float min_dist = controller->get_braking_distance()*1.3+approach_margin*2;
864 BlockIter block = start;
865 list<BlockIter>::iterator good_end = blocks.end();
866 Track *divert_track = 0;
867 bool try_divert = false;
868 Train *blocking_train = 0;
869 BlockList contested_blocks;
871 SetFlag setf(reserving);
875 BlockIter last = block;
876 block = block.next(cur_route!=routes.end() ? cur_route->route : 0);
877 if(!block || block->get_endpoints().size()<2)
880 good_end = blocks.end();
884 TrackIter track = block.track_iter();
886 if(cur_route!=routes.end())
888 if(!advance_route(cur_route, *track))
890 // Keep the blocks if we arrived at the end of the route
893 good_end = blocks.end();
900 if(block->get_turnout_id() && !last->get_turnout_id())
902 /* We can keep the blocks if we arrive at a turnout from a non-turnout
903 block. Having a turnout block as our last reserved block is not good
904 as it would limit our diversion possibilities for little benefit. */
905 good_end = blocks.end();
906 if(nsens>=3 && dist>=min_dist)
912 if(block->get_train()!=blocking_train)
914 if(blocking_train->free_block(*contested_blocks.back()))
916 // Roll back and start actually reserving the blocks
917 block = blocks.back();
918 cur_route = routes.begin();
919 advance_route(cur_route, *block.track_iter().track());
920 if(blocking_train->get_priority()==priority)
921 blocking_train->yield_to(*this);
927 yield_to(*blocking_train);
928 pending_block = contested_blocks.front().block();
929 try_divert = divert_track;
935 contested_blocks.push_back(block);
940 bool reserved = block->reserve(this);
943 /* We've found another train. If it wants to exit the block from the
944 same endpoint we're trying to enter from or the other way around,
945 treat it as coming towards us. Otherwise treat it as going in the
947 Train *other_train = block->get_train();
948 int other_entry = other_train->get_entry_to_block(*block);
950 throw LogicError("Block reservation inconsistency");
952 unsigned exit = block.reverse().entry();
953 unsigned other_exit = BlockIter(block.block(), other_entry).reverse().entry();
954 bool entry_conflict = (block.entry()==other_exit);
955 bool exit_conflict = (exit==static_cast<unsigned>(other_entry));
956 if(!entry_conflict && !last->get_turnout_id())
958 /* The other train is not coming to the blocks we're holding, so we
960 good_end = blocks.end();
962 if(static_cast<unsigned>(other_entry)==block.entry())
963 preceding_train = other_train;
966 int other_prio = other_train->get_priority();
968 if(!entry_conflict && !exit_conflict && other_prio<priority)
970 /* Ask a lesser priority train going to the same direction to free
972 if(other_train->free_block(*block))
973 reserved = block->reserve(this);
975 else if(other_train!=yielding_to && (other_prio<priority || (other_prio==priority && entry_conflict)))
977 /* A lesser priority train is coming at us, we must ask it to free
978 enough blocks to get clear of it to avoid a potential deadlock */
979 blocking_train = other_train;
980 contested_blocks.clear();
981 contested_blocks.push_back(block);
984 else if(divert_track && (entry_conflict || exit_conflict))
985 // We are blocked, but there's a diversion possibility
990 pending_block = &*block;
995 if(block->get_turnout_id())
997 const TrackType::Endpoint &track_ep = track.endpoint();
998 bool multiple_paths = (track_ep.paths&(track_ep.paths-1));
1000 if(multiple_paths && cur_route!=routes.end() && cur_route->diversion!=block->get_turnout_id())
1001 /* There's multiple paths to be taken and we are on a route - take
1002 note of the diversion possibility */
1003 divert_track = &*track;
1006 if(!contested_blocks.empty() && contested_blocks.front()==block)
1007 contested_blocks.pop_front();
1009 blocks.push_back(block);
1011 if(cur_blocks_end==blocks.end())
1013 if(clear_blocks_end==blocks.end())
1015 if(good_end==blocks.end())
1018 if(block->get_sensor_id())
1021 dist += block->get_path_length(block.entry());
1024 // Unreserve blocks that were not good
1025 release_blocks(good_end, blocks.end());
1027 if(blocks.back()!=start)
1028 // We got some new blocks, so no longer need to yield
1031 check_turnout_paths(true);
1033 // Make any sensorless blocks at the beginning immediately current
1034 while(cur_blocks_end!=clear_blocks_end && !(*cur_blocks_end)->get_sensor_id())
1037 if(try_divert && divert(*divert_track))
1041 void Train::check_turnout_paths(bool set)
1043 if(clear_blocks_end==blocks.end())
1046 for(list<BlockIter>::iterator i=clear_blocks_end; i!=blocks.end(); ++i)
1048 if((*i)->get_turnout_id())
1050 TrackIter track = i->track_iter();
1051 const TrackType::Endpoint &track_ep = track.endpoint();
1054 list<BlockIter>::iterator j = i;
1055 if(++j!=blocks.end())
1057 TrackIter rev = j->track_iter().flip();
1058 unsigned mask = rev.endpoint().paths&track_ep.paths;
1059 for(path=0; mask>1; mask>>=1, ++path) ;
1064 if(path!=track->get_active_path())
1067 track->set_active_path(path);
1069 /* Check again, in case the driver was able to service the request
1071 if(!set || path!=track->get_active_path())
1076 if(i==clear_blocks_end)
1081 float Train::get_reserved_distance_until(const Block *until_block, bool back) const
1086 Vehicle &veh = *(reverse!=back ? vehicles.back() : vehicles.front());
1087 const VehicleType &vtype = veh.get_type();
1089 TrackIter track(veh.get_track(), veh.get_entry());
1090 if(!track) // XXX Probably unnecessary
1093 BlockList::const_iterator block = blocks.begin();
1094 while(block!=clear_blocks_end && !(*block)->has_track(*track))
1096 if(block==clear_blocks_end || &**block==until_block)
1099 float result = veh.get_offset();
1101 track = track.reverse();
1103 result = track->get_type().get_path_length(track->get_active_path())-result;
1104 result -= vtype.get_length()/2;
1108 track = track.next();
1112 if(!(*block)->has_track(*track))
1116 if(block==blocks.begin())
1123 if(block==clear_blocks_end)
1127 if(&**block==until_block)
1131 result += track->get_type().get_path_length(track->get_active_path());
1137 float Train::get_real_speed(unsigned i) const
1141 if(real_speed[i].weight)
1142 return real_speed[i].speed;
1146 for(low=i; low>0; --low)
1147 if(real_speed[low].weight)
1149 for(high=i; high+1<real_speed.size(); ++high)
1150 if(real_speed[high].weight)
1153 if(real_speed[high].weight)
1155 if(real_speed[low].weight)
1157 float f = float(i-low)/(high-low);
1158 return real_speed[low].speed*(1-f)+real_speed[high].speed*f;
1161 return real_speed[high].speed*float(i)/high;
1163 else if(real_speed[low].weight)
1164 return real_speed[low].speed*float(i)/low;
1169 unsigned Train::find_speed_step(float real) const
1171 if(real_speed.size()<=1)
1173 if(real<=real_speed[1].speed*0.5)
1179 for(unsigned i=0; (!high && i<real_speed.size()); ++i)
1180 if(real_speed[i].weight)
1183 if(real_speed[i].speed<real)
1190 unsigned limit = real_speed.size()/5;
1198 return min(min(static_cast<unsigned>(low*real/real_speed[low].speed), real_speed.size()-1), last+limit);
1201 float f = (real-real_speed[low].speed)/(real_speed[high].speed-real_speed[low].speed);
1202 return static_cast<unsigned>(low*(1-f)+high*f+0.5);
1205 float Train::get_travel_speed() const
1207 float speed = get_real_speed(current_speed_step);
1208 float scale = layout.get_catalogue().get_scale();
1209 return static_cast<int>(round(speed/scale*3.6/5))*5;
1212 void Train::set_status(const string &s)
1215 signal_status_changed.emit(s);
1218 void Train::release_blocks()
1220 release_blocks(blocks.begin(), blocks.end());
1223 void Train::release_blocks(BlockList::iterator begin, BlockList::iterator end)
1227 if(begin==cur_blocks_end)
1228 cur_blocks_end = end;
1229 if(begin==clear_blocks_end)
1230 clear_blocks_end = end;
1232 Block &block = **begin;
1233 blocks.erase(begin++);
1236 if(begin==blocks.end())
1237 end_of_route = false;
1241 void Train::reverse_blocks(BlockList &blks) const
1244 for(BlockList::iterator i=blks.begin(); i!=blks.end(); ++i)
1248 bool Train::advance_route(list<RouteRef>::iterator &iter, Track &track)
1250 while(iter!=routes.end() && !iter->route->has_track(track))
1252 if(iter==routes.end())
1255 list<RouteRef>::iterator next = iter;
1257 if(next!=routes.end() && next->diversion && next->route->has_track(track))
1263 Route *Train::create_lead_route(Route *lead, const Route *target)
1267 lead = new Route(layout);
1268 lead->set_name("Lead");
1269 lead->set_temporary(true);
1272 set<Track *> tracks;
1273 for(BlockList::iterator i=blocks.begin(); i!=blocks.end(); ++i)
1275 const set<Track *> &btracks = (*i)->get_tracks();
1276 for(set<Track *>::const_iterator j=btracks.begin(); j!=btracks.end(); ++j)
1277 if(!target || !target->has_track(**j))
1281 lead->add_tracks(tracks);
1286 bool Train::is_valid_diversion(const Route &diversion, const TrackIter &from)
1288 float diversion_len = 0;
1289 TrackLoopIter track1 = from;
1290 while(diversion.has_track(*track1))
1292 unsigned path = diversion.get_path(*track1);
1293 diversion_len += track1->get_type().get_path_length(path);
1295 track1 = track1.next(path);
1301 list<RouteRef>::iterator route = routes.begin();
1302 if(!advance_route(route, *from))
1305 float route_len = 0;
1306 TrackLoopIter track2 = from;
1309 unsigned path = route->route->get_path(*track2);
1310 route_len += track2->get_type().get_path_length(path);
1312 bool ok = (track2!=from && diversion.has_track(*track2));
1314 track2 = track2.next(path);
1322 if(!advance_route(route, *track2))
1326 // Must end up at the same place through both routes
1330 return diversion_len<route_len*1.2;
1334 Train::RouteRef::RouteRef(const Route *r, unsigned d):
1340 Train::RealSpeed::RealSpeed():
1345 void Train::RealSpeed::add(float s, float w)
1347 speed = (speed*weight+s*w)/(weight+w);
1348 weight = min(weight+w, 300.0f);
1352 Train::Loader::Loader(Train &t):
1353 DataFile::BasicLoader<Train>(t),
1357 add("block", &Loader::block);
1358 add("block_hint", &Loader::block_hint);
1359 add("name", &Loader::name);
1360 add("priority", &Train::priority);
1361 add("real_speed", &Loader::real_speed);
1362 add("route", &Loader::route);
1363 add("timetable", &Loader::timetable);
1364 add("vehicle", &Loader::vehicle);
1367 void Train::Loader::finish()
1369 if(!obj.blocks.empty())
1371 TrackIter track = obj.blocks.front().track_iter();
1372 float offset = 2*obj.layout.get_catalogue().get_scale();
1373 obj.vehicles.back()->place(*track, track.entry(), offset, Vehicle::BACK_BUFFER);
1375 obj.set_status("Stopped");
1379 void Train::Loader::block(unsigned id)
1387 blk = &obj.layout.get_block(id);
1389 catch(const KeyError &)
1391 blocks_valid = false;
1397 entry = blk->get_endpoint_by_link(*prev_block);
1402 obj.blocks.push_back(BlockIter(blk, entry));
1404 if(blk->get_sensor_id())
1405 obj.layout.get_driver().set_sensor(blk->get_sensor_id(), true);
1410 void Train::Loader::block_hint(unsigned id)
1414 prev_block = &obj.layout.get_block(id);
1416 catch(const KeyError &)
1418 blocks_valid = false;
1422 void Train::Loader::name(const string &n)
1427 void Train::Loader::real_speed(unsigned i, float speed, float weight)
1429 if(i>=obj.real_speed.size())
1431 obj.real_speed[i].speed = speed;
1432 obj.real_speed[i].weight = weight;
1435 void Train::Loader::route(const string &n)
1437 obj.set_route(&obj.layout.get_route(n));
1440 void Train::Loader::timetable()
1443 throw InvalidState("A timetable has already been loaded");
1445 obj.timetable = new Timetable(obj);
1446 load_sub(*obj.timetable);
1449 void Train::Loader::vehicle(ArticleNumber art_nr)
1451 const VehicleType &vtype = obj.layout.get_catalogue().get_vehicle(art_nr);
1452 Vehicle *veh = new Vehicle(obj.layout, vtype);
1453 obj.vehicles.back()->attach_back(*veh);
1454 obj.vehicles.push_back(veh);