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):
51 cur_blocks_end(blocks.end()),
52 clear_blocks_end(blocks.end()),
56 controller(new AIControl(*this, new SimpleController)),
59 current_speed_step(0),
60 speed_changing(false),
67 real_speed(layout.get_driver().get_protocol_speed_steps(protocol)+1),
68 accurate_position(false),
71 if(!loco_type.is_locomotive())
72 throw InvalidParameterValue("Initial vehicle must be a locomotive");
74 vehicles.push_back(new Vehicle(layout, loco_type));
76 layout.add_train(*this);
78 layout.get_driver().add_loco(address, protocol);
79 layout.get_driver().signal_loco_speed.connect(sigc::mem_fun(this, &Train::loco_speed_event));
80 layout.get_driver().signal_loco_function.connect(sigc::mem_fun(this, &Train::loco_func_event));
82 layout.signal_block_reserved.connect(sigc::mem_fun(this, &Train::block_reserved));
83 layout.get_driver().signal_sensor.connect(sigc::mem_fun(this, &Train::sensor_event));
85 layout.get_driver().signal_halt.connect(sigc::mem_fun(this, &Train::halt_event));
87 const set<Track *> &tracks = layout.get_tracks();
88 for(set<Track *>::const_iterator i=tracks.begin(); i!=tracks.end(); ++i)
89 if((*i)->get_turnout_id())
90 (*i)->signal_path_changed.connect(sigc::hide(sigc::bind(sigc::mem_fun(this, &Train::turnout_path_changed), sigc::ref(**i))));
92 controller->signal_control_changed.connect(sigc::mem_fun(this, &Train::control_changed));
99 for(vector<Vehicle *>::iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
101 layout.remove_train(*this);
104 void Train::set_name(const string &n)
108 signal_name_changed.emit(name);
111 void Train::set_priority(int p)
116 void Train::yield_to(const Train &t)
121 void Train::add_vehicle(const VehicleType &vt)
123 Vehicle *veh = new Vehicle(layout, vt);
124 vehicles.back()->attach_back(*veh);
125 vehicles.push_back(veh);
128 void Train::remove_vehicle(unsigned i)
130 if(i>=vehicles.size())
131 throw InvalidParameterValue("Vehicle index out of range");
133 throw InvalidParameterValue("Can't remove the locomotive");
135 vehicles.erase(vehicles.begin()+i);
136 if(i<vehicles.size())
137 vehicles[i-1]->attach_back(*vehicles[i]);
140 unsigned Train::get_n_vehicles() const
142 return vehicles.size();
145 Vehicle &Train::get_vehicle(unsigned i)
147 if(i>=vehicles.size())
148 throw InvalidParameterValue("Vehicle index out of range");
152 const Vehicle &Train::get_vehicle(unsigned i) const
154 if(i>=vehicles.size())
155 throw InvalidParameterValue("Vehicle index out of range");
159 void Train::set_control(const string &n, float v)
161 controller->set_control(n, v);
164 void Train::set_active(bool a)
168 if(!a && controller->get_speed())
169 throw InvalidState("Can't deactivate while moving");
174 stop_timeout = Time::TimeStamp();
179 stop_timeout = Time::now()+2*Time::sec;
180 set_status("Stopped");
184 void Train::set_function(unsigned func, bool state)
186 if(!loco_type.get_functions().count(func))
187 throw InvalidParameterValue("Invalid function");
189 layout.get_driver().set_loco_function(address, func, state);
191 layout.get_driver().set_loco_function(address+1, func-4, state);
194 float Train::get_control(const string &ctrl) const
196 return controller->get_control(ctrl).value;
199 float Train::get_speed() const
201 return controller->get_speed();
204 bool Train::get_function(unsigned func) const
206 return (functions>>func)&1;
209 void Train::set_timetable(Timetable *tt)
215 bool Train::set_route(const Route *r)
217 free_noncritical_blocks();
220 if(r && !blocks.empty())
222 TrackIter first = blocks.front().track_iter();
223 TrackIter next = blocks.back().next().track_iter();
224 if(!r->has_track(*next))
226 lead = Route::find(next, *r);
229 create_lead_route(lead, lead);
230 routes.push_front(lead);
232 else if(!r->has_track(*first))
233 lead = create_lead_route(0, r);
238 routes.push_back(lead);
241 end_of_route = false;
245 signal_route_changed.emit(get_route());
250 bool Train::go_to(Track &to)
252 for(BlockList::const_iterator i=blocks.begin(); i!=cur_blocks_end; ++i)
253 if((*i)->has_track(to))
255 signal_arrived.emit();
259 free_noncritical_blocks();
261 TrackIter next = blocks.back().next().track_iter();
263 Route *route = Route::find(next, to);
266 create_lead_route(route, route);
267 return set_route(route);
270 bool Train::go_to(const Zone &to)
273 for(BlockList::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
274 tracks.insert((*i)->get_tracks().begin(), (*i)->get_tracks().end());
276 const Zone::TrackSet &ztracks = to.get_tracks();
277 unsigned union_size = 0;
278 for(Zone::TrackSet::const_iterator i=ztracks.begin(); i!=ztracks.end(); ++i)
279 union_size += tracks.count(*i);
281 if(union_size==tracks.size() || union_size==ztracks.size())
283 signal_arrived.emit();
287 free_noncritical_blocks();
289 TrackIter next = blocks.back().next().track_iter();
291 Route *route = Route::find(next, to);
294 create_lead_route(route, route);
295 route->add_tracks(ztracks);
296 return set_route(route);
299 bool Train::divert(Track &from)
301 if(!from.get_turnout_id())
302 throw InvalidParameterValue("Can't divert from a non-turnout");
308 list<RouteRef>::iterator route = routes.begin();
310 // Follow our routes to find out where we're entering the turnout
311 for(TrackLoopIter track = blocks.front().track_iter();;)
313 if(!advance_route(route, *track))
318 Block &block = track->get_block();
319 if(block.get_train()==this && !free_block(block))
322 int route_path = route->route->get_turnout(from.get_turnout_id());
324 // Check that more than one path is available
325 unsigned ep_paths = track.endpoint().paths;
326 if(!(ep_paths&(ep_paths-1)))
329 // Choose some other path
330 for(int i=0; ep_paths>>i; ++i)
331 if((ep_paths&(1<<i)) && i!=route_path)
337 entry = track.entry();
341 track = track.next(route->route->get_path(*track));
343 if(!track || track.looped())
347 TrackIter track = TrackIter(&from, entry).next(path);
352 for(list<RouteRef>::iterator i=routes.begin(); i!=routes.end(); ++i)
353 tracks.insert(i->route->get_tracks().begin(), i->route->get_tracks().end());
354 RefPtr<Route> diversion = Route::find(track, tracks);
358 diversion->set_name("Diversion");
359 diversion->add_track(from);
360 diversion->set_turnout(from.get_turnout_id(), path);
362 if(!is_valid_diversion(*diversion, TrackIter(&from, entry)))
365 // Follow the diversion route until we get back to the original route
366 list<RouteRef>::iterator end = routes.end();
369 for(list<RouteRef>::iterator i=route; (end==routes.end() && i!=routes.end()); ++i)
370 if(i->route->has_track(*track))
373 if(end!=routes.end())
375 else if(!diversion->has_track(*track))
376 throw LogicError("Pathfinder returned a bad route");
378 track = track.next(diversion->get_path(*track));
382 // We are rejoining the same route we diverted from, duplicate it
383 routes.insert(end, *route);
387 routes.erase(route, end);
389 routes.insert(end, RouteRef(diversion.release(), from.get_turnout_id()));
394 const Route *Train::get_route() const
398 return routes.front().route;
401 void Train::place(Block &block, unsigned entry)
403 if(controller->get_speed())
404 throw InvalidState("Must be stopped before placing");
409 accurate_position = false;
411 if(!block.reserve(this))
413 set_status("Unplaced");
417 blocks.push_back(BlockIter(&block, entry));
420 TrackIter track = BlockIter(&block, entry).reverse().track_iter();
421 vehicles.front()->place(*track, track.entry(), 0, Vehicle::FRONT_BUFFER);
425 const Block::Endpoint &bep = block.get_endpoint(entry);
426 vehicles.back()->place(*bep.track, bep.track_ep, 0, Vehicle::BACK_BUFFER);
430 void Train::unplace()
432 if(controller->get_speed())
433 throw InvalidState("Must be stopped before unplacing");
438 accurate_position = false;
440 for(vector<Vehicle *>::iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
443 set_status("Unplaced");
446 bool Train::free_block(Block &block)
448 float margin = 10*layout.get_catalogue().get_scale();
449 if(get_reserved_distance_until(&block, false)<controller->get_braking_distance()*1.3+margin)
453 for(BlockList::iterator i=cur_blocks_end; i!=blocks.end(); ++i)
455 if(i->block()==&block)
459 release_blocks(i, blocks.end());
462 else if((*i)->get_sensor_id())
469 void Train::free_noncritical_blocks()
474 if(controller->get_speed()==0)
476 release_blocks(cur_blocks_end, blocks.end());
480 float margin = 10*layout.get_catalogue().get_scale();
481 float min_dist = controller->get_braking_distance()*1.3+margin;
483 Vehicle &veh = *(reverse ? vehicles.back() : vehicles.front());
485 TrackIter track(veh.get_track(), veh.get_entry());
486 BlockList::iterator block = blocks.begin();
488 while(block!=blocks.end() && !(*block)->has_track(*track))
491 if(block==cur_blocks_end)
495 float dist = veh.get_offset();
499 dist = track->get_type().get_path_length(track->get_active_path())-dist;
500 dist -= veh.get_type().get_length()/2;
505 track = track.next();
507 if(!(*block)->has_track(*track))
510 if(block==cur_blocks_end)
512 if(block==blocks.end())
515 if(dist>min_dist && nsens>0)
517 release_blocks(block, blocks.end());
521 if(in_rsv && (*block)->get_sensor_id())
525 dist += track->get_type().get_path_length(track->get_active_path());
529 int Train::get_entry_to_block(Block &block) const
531 for(BlockList::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
532 if(i->block()==&block)
537 float Train::get_reserved_distance() const
539 return get_reserved_distance_until(0, false);
542 void Train::tick(const Time::TimeStamp &t, const Time::TimeDelta &dt)
544 if(!active && stop_timeout && t>=stop_timeout)
546 release_blocks(cur_blocks_end, blocks.end());
547 stop_timeout = Time::TimeStamp();
550 Driver &driver = layout.get_driver();
554 controller->tick(dt);
555 float speed = controller->get_speed();
556 unsigned speed_step = find_speed_step(speed);
558 if(controller->get_reverse()!=reverse)
560 reverse = controller->get_reverse();
561 driver.set_loco_reverse(address, reverse);
563 release_blocks(cur_blocks_end, blocks.end());
564 reverse_blocks(blocks);
568 if(speed_step!=current_speed_step && !speed_changing && !driver.is_halted() && driver.get_power())
570 speed_changing = true;
571 driver.set_loco_speed(address, speed_step);
576 set_status(format("Traveling %d kmh", get_travel_speed()));
578 set_status("Waiting");
586 Vehicle &vehicle = *(reverse ? vehicles.back() : vehicles.front());
587 Track *track = vehicle.get_track();
590 for(BlockList::const_iterator i=blocks.begin(); (!ok && i!=cur_blocks_end); ++i)
591 ok = (*i)->has_track(*track);
594 if(real_speed.size()>1)
595 d = get_real_speed(current_speed_step)*(dt/Time::sec);
597 d = speed*(dt/Time::sec);
600 SetFlag setf(advancing);
601 vehicle.advance(reverse ? -d : d);
603 else if(accurate_position)
606 if(overshoot_dist>40*layout.get_catalogue().get_scale())
608 layout.emergency(name+" has not arrived at sensor");
609 accurate_position = false;
613 else if(end_of_route && cur_blocks_end==blocks.end())
616 signal_arrived.emit();
620 if(!blocks.empty() && !blocks.front()->get_sensor_id())
622 float dist = get_reserved_distance_until(&*blocks.front(), true);
624 if(dist>10*layout.get_catalogue().get_scale())
626 blocks.front()->reserve(0);
632 void Train::save(list<DataFile::Statement> &st) const
634 st.push_back((DataFile::Statement("name"), name));
636 st.push_back((DataFile::Statement("priority"), priority));
638 for(vector<Vehicle *>::const_iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
639 if(i!=vehicles.begin())
640 st.push_back((DataFile::Statement("vehicle"), (*i)->get_type().get_article_number()));
642 for(unsigned i=0; i<real_speed.size(); ++i)
643 if(real_speed[i].weight)
644 st.push_back((DataFile::Statement("real_speed"), i, real_speed[i].speed, real_speed[i].weight));
646 if(!blocks.empty() && cur_blocks_end!=blocks.begin())
648 BlockList blks(blocks.begin(), BlockList::const_iterator(cur_blocks_end));
650 reverse_blocks(blks);
652 BlockIter prev = blks.front().flip();
653 st.push_back((DataFile::Statement("block_hint"), prev->get_id()));
655 for(BlockList::const_iterator i=blks.begin(); i!=blks.end(); ++i)
656 st.push_back((DataFile::Statement("block"), (*i)->get_id()));
661 list<RouteRef>::const_iterator i = routes.begin();
662 for(; (i!=routes.end() && i->route->is_temporary()); ++i) ;
664 st.push_back((DataFile::Statement("route"), i->route->get_name()));
669 DataFile::Statement ss("timetable");
670 timetable->save(ss.sub);
675 void Train::control_changed(const Controller::Control &ctrl)
677 signal_control_changed.emit(ctrl.name, ctrl.value);
680 void Train::loco_speed_event(unsigned addr, unsigned speed, bool)
684 current_speed_step = speed;
685 speed_changing = false;
690 void Train::loco_func_event(unsigned addr, unsigned func, bool state)
692 if(addr==address || (addr==address+1 && loco_type.get_max_function()>4))
697 functions |= 1<<func;
699 functions &= ~(1<<func);
701 signal_function_changed.emit(func, state);
705 void Train::sensor_event(unsigned addr, bool state)
709 // Find the first sensor block from our reserved blocks that isn't this sensor
710 BlockList::iterator end;
712 for(end=cur_blocks_end; end!=blocks.end(); ++end)
713 if((*end)->get_sensor_id())
715 if((*end)->get_sensor_id()!=addr)
730 // Compute speed and update related state
731 float travel_time_secs = (Time::now()-last_entry_time)/Time::sec;
735 if(current_speed_step>0)
737 RealSpeed &rs = real_speed[current_speed_step];
738 rs.add(travel_dist/travel_time_secs, travel_time_secs);
740 set_status(format("Traveling %d kmh", get_travel_speed()));
744 for(BlockList::iterator j=cur_blocks_end; j!=end; ++j)
746 travel_dist += (*j)->get_path_length(j->entry());
748 if((*j)->get_sensor_id()==addr && !advancing)
750 TrackIter track = j->track_iter();
753 track = track.flip();
754 vehicles.back()->place(*track, track.entry(), 0, Vehicle::BACK_AXLE);
757 vehicles.front()->place(*track, track.entry(), 0, Vehicle::FRONT_AXLE);
760 last_entry_time = Time::now();
762 accurate_position = true;
765 // Check if we've reached the next route
768 const Route &route = *(++routes.begin())->route;
769 for(BlockList::iterator j=cur_blocks_end; j!=end; ++j)
770 if(route.has_track(*j->track_iter()))
774 signal_route_changed.emit(routes.front().route);
779 // Move blocks up to the next sensor to our current blocks
780 cur_blocks_end = end;
782 // Try to get more blocks if we're moving
787 layout.emergency("Sensor for "+name+" triggered out of order");
791 const Vehicle &veh = *(reverse ? vehicles.front() : vehicles.back());
793 // Find the first sensor in our current blocks that's still active
794 BlockList::iterator end = blocks.begin();
795 for(BlockList::iterator i=blocks.begin(); i!=cur_blocks_end; ++i)
797 if((*i)->has_track(*veh.get_track()))
799 if((*i)->get_sensor_id())
801 if(layout.get_driver().get_sensor((*i)->get_sensor_id()))
811 if(end!=blocks.begin() && end!=cur_blocks_end)
812 // Free blocks up to the last inactive sensor
813 release_blocks(blocks.begin(), end);
817 void Train::turnout_path_changed(Track &track)
819 for(list<BlockIter>::iterator i=blocks.begin(); i!=blocks.end(); ++i)
820 if((*i)->get_turnout_id()==track.get_turnout_id() && !reserving)
821 check_turnout_paths(false);
824 void Train::halt_event(bool h)
827 accurate_position = false;
830 void Train::block_reserved(const Block &block, const Train *train)
832 if(&block==pending_block && !train && !reserving)
836 void Train::reserve_more()
838 if(!active || blocks.empty() || end_of_route)
841 BlockIter start = blocks.back();
845 // See how many sensor blocks and how much track we already have
848 for(BlockList::const_iterator i=cur_blocks_end; i!=blocks.end(); ++i)
850 if((*i)->get_sensor_id())
853 dist += (*i)->get_path_length(i->entry());
856 list<RouteRef>::iterator cur_route = routes.begin();
857 advance_route(cur_route, *start.track_iter());
859 float approach_margin = 50*layout.get_catalogue().get_scale();
860 float min_dist = controller->get_braking_distance()*1.3+approach_margin*2;
862 BlockIter block = start;
863 list<BlockIter>::iterator good_end = blocks.end();
864 Track *divert_track = 0;
865 bool try_divert = false;
866 Train *blocking_train = 0;
867 BlockList contested_blocks;
869 SetFlag setf(reserving);
873 BlockIter last = block;
874 block = block.next(cur_route!=routes.end() ? cur_route->route : 0);
875 if(!block || block->get_endpoints().size()<2)
878 good_end = blocks.end();
882 TrackIter track = block.track_iter();
884 if(cur_route!=routes.end())
886 if(!advance_route(cur_route, *track))
888 // Keep the blocks if we arrived at the end of the route
891 good_end = blocks.end();
898 if(block->get_turnout_id() && !last->get_turnout_id())
900 /* We can keep the blocks if we arrive at a turnout from a non-turnout
901 block. Having a turnout block as our last reserved block is not good
902 as it would limit our diversion possibilities for little benefit. */
903 good_end = blocks.end();
904 if(nsens>=3 && dist>=min_dist)
910 if(block->get_train()!=blocking_train)
912 if(blocking_train->free_block(*contested_blocks.back()))
914 // Roll back and start actually reserving the blocks
915 block = blocks.back();
916 cur_route = routes.begin();
917 advance_route(cur_route, *block.track_iter().track());
918 if(blocking_train->get_priority()==priority)
919 blocking_train->yield_to(*this);
925 yield_to(*blocking_train);
926 pending_block = contested_blocks.front().block();
927 try_divert = divert_track;
933 contested_blocks.push_back(block);
938 bool reserved = block->reserve(this);
941 /* We've found another train. If it wants to exit the block from the
942 same endpoint we're trying to enter from or the other way around,
943 treat it as coming towards us. Otherwise treat it as going in the
945 Train *other_train = block->get_train();
946 int other_entry = other_train->get_entry_to_block(*block);
948 throw LogicError("Block reservation inconsistency");
950 unsigned exit = block.reverse().entry();
951 unsigned other_exit = BlockIter(block.block(), other_entry).reverse().entry();
952 bool entry_conflict = (block.entry()==other_exit);
953 bool exit_conflict = (exit==static_cast<unsigned>(other_entry));
954 if(!entry_conflict && !last->get_turnout_id())
955 /* The other train is not coming to the blocks we're holding, so we
957 good_end = blocks.end();
959 int other_prio = other_train->get_priority();
961 if(!entry_conflict && !exit_conflict && other_prio<priority)
963 /* Ask a lesser priority train going to the same direction to free
965 if(other_train->free_block(*block))
966 reserved = block->reserve(this);
968 else if(other_train!=yielding_to && (other_prio<priority || (other_prio==priority && entry_conflict)))
970 /* A lesser priority train is coming at us, we must ask it to free
971 enough blocks to get clear of it to avoid a potential deadlock */
972 blocking_train = other_train;
973 contested_blocks.clear();
974 contested_blocks.push_back(block);
977 else if(divert_track && (entry_conflict || exit_conflict))
978 // We are blocked, but there's a diversion possibility
983 pending_block = &*block;
988 if(block->get_turnout_id())
990 const TrackType::Endpoint &track_ep = track.endpoint();
991 bool multiple_paths = (track_ep.paths&(track_ep.paths-1));
993 if(multiple_paths && cur_route!=routes.end() && cur_route->diversion!=block->get_turnout_id())
994 /* There's multiple paths to be taken and we are on a route - take
995 note of the diversion possibility */
996 divert_track = &*track;
999 if(!contested_blocks.empty() && contested_blocks.front()==block)
1000 contested_blocks.pop_front();
1002 blocks.push_back(block);
1004 if(cur_blocks_end==blocks.end())
1006 if(clear_blocks_end==blocks.end())
1008 if(good_end==blocks.end())
1011 if(block->get_sensor_id())
1014 dist += block->get_path_length(block.entry());
1017 // Unreserve blocks that were not good
1018 release_blocks(good_end, blocks.end());
1020 if(blocks.back()!=start)
1021 // We got some new blocks, so no longer need to yield
1024 check_turnout_paths(true);
1026 // Make any sensorless blocks at the beginning immediately current
1027 while(cur_blocks_end!=clear_blocks_end && !(*cur_blocks_end)->get_sensor_id())
1030 if(try_divert && divert(*divert_track))
1034 void Train::check_turnout_paths(bool set)
1036 if(clear_blocks_end==blocks.end())
1039 for(list<BlockIter>::iterator i=clear_blocks_end; i!=blocks.end(); ++i)
1041 if((*i)->get_turnout_id())
1043 TrackIter track = i->track_iter();
1044 const TrackType::Endpoint &track_ep = track.endpoint();
1047 list<BlockIter>::iterator j = i;
1048 if(++j!=blocks.end())
1050 TrackIter rev = j->track_iter().flip();
1051 unsigned mask = rev.endpoint().paths&track_ep.paths;
1052 for(path=0; mask>1; mask>>=1, ++path) ;
1057 if(path!=track->get_active_path())
1060 track->set_active_path(path);
1062 /* Check again, in case the driver was able to service the request
1064 if(!set || path!=track->get_active_path())
1069 if(i==clear_blocks_end)
1074 float Train::get_reserved_distance_until(const Block *until_block, bool back) const
1079 Vehicle &veh = *(reverse!=back ? vehicles.back() : vehicles.front());
1080 const VehicleType &vtype = veh.get_type();
1082 TrackIter track(veh.get_track(), veh.get_entry());
1083 if(!track) // XXX Probably unnecessary
1086 BlockList::const_iterator block = blocks.begin();
1087 while(block!=clear_blocks_end && !(*block)->has_track(*track))
1089 if(block==clear_blocks_end || &**block==until_block)
1092 float result = veh.get_offset();
1094 track = track.reverse();
1096 result = track->get_type().get_path_length(track->get_active_path())-result;
1097 result -= vtype.get_length()/2;
1101 track = track.next();
1105 if(!(*block)->has_track(*track))
1109 if(block==blocks.begin())
1116 if(block==clear_blocks_end)
1120 if(&**block==until_block)
1124 result += track->get_type().get_path_length(track->get_active_path());
1130 float Train::get_real_speed(unsigned i) const
1134 if(real_speed[i].weight)
1135 return real_speed[i].speed;
1139 for(low=i; low>0; --low)
1140 if(real_speed[low].weight)
1142 for(high=i; high+1<real_speed.size(); ++high)
1143 if(real_speed[high].weight)
1146 if(real_speed[high].weight)
1148 if(real_speed[low].weight)
1150 float f = float(i-low)/(high-low);
1151 return real_speed[low].speed*(1-f)+real_speed[high].speed*f;
1154 return real_speed[high].speed*float(i)/high;
1156 else if(real_speed[low].weight)
1157 return real_speed[low].speed*float(i)/low;
1162 unsigned Train::find_speed_step(float real) const
1164 if(real_speed.size()<=1)
1166 if(real<=real_speed[1].speed*0.5)
1172 for(unsigned i=0; (!high && i<real_speed.size()); ++i)
1173 if(real_speed[i].weight)
1176 if(real_speed[i].speed<real)
1183 unsigned limit = real_speed.size()/5;
1191 return min(min(static_cast<unsigned>(low*real/real_speed[low].speed), real_speed.size()-1), last+limit);
1194 float f = (real-real_speed[low].speed)/(real_speed[high].speed-real_speed[low].speed);
1195 return static_cast<unsigned>(low*(1-f)+high*f+0.5);
1198 float Train::get_travel_speed() const
1200 float speed = get_real_speed(current_speed_step);
1201 float scale = layout.get_catalogue().get_scale();
1202 return static_cast<int>(round(speed/scale*3.6/5))*5;
1205 void Train::set_status(const string &s)
1208 signal_status_changed.emit(s);
1211 void Train::release_blocks()
1213 release_blocks(blocks.begin(), blocks.end());
1216 void Train::release_blocks(BlockList::iterator begin, BlockList::iterator end)
1220 if(begin==cur_blocks_end)
1221 cur_blocks_end = end;
1222 if(begin==clear_blocks_end)
1223 clear_blocks_end = end;
1225 Block &block = **begin;
1226 blocks.erase(begin++);
1229 if(begin==blocks.end())
1230 end_of_route = false;
1234 void Train::reverse_blocks(BlockList &blks) const
1237 for(BlockList::iterator i=blks.begin(); i!=blks.end(); ++i)
1241 bool Train::advance_route(list<RouteRef>::iterator &iter, Track &track)
1243 while(iter!=routes.end() && !iter->route->has_track(track))
1245 if(iter==routes.end())
1248 list<RouteRef>::iterator next = iter;
1250 if(next!=routes.end() && next->diversion && next->route->has_track(track))
1256 Route *Train::create_lead_route(Route *lead, const Route *target)
1260 lead = new Route(layout);
1261 lead->set_name("Lead");
1262 lead->set_temporary(true);
1265 set<Track *> tracks;
1266 for(BlockList::iterator i=blocks.begin(); i!=blocks.end(); ++i)
1268 const set<Track *> &btracks = (*i)->get_tracks();
1269 for(set<Track *>::const_iterator j=btracks.begin(); j!=btracks.end(); ++j)
1270 if(!target || !target->has_track(**j))
1274 lead->add_tracks(tracks);
1279 bool Train::is_valid_diversion(const Route &diversion, const TrackIter &from)
1281 float diversion_len = 0;
1282 TrackLoopIter track1 = from;
1283 while(diversion.has_track(*track1))
1285 unsigned path = diversion.get_path(*track1);
1286 diversion_len += track1->get_type().get_path_length(path);
1288 track1 = track1.next(path);
1294 list<RouteRef>::iterator route = routes.begin();
1295 if(!advance_route(route, *from))
1298 float route_len = 0;
1299 TrackLoopIter track2 = from;
1302 unsigned path = route->route->get_path(*track2);
1303 route_len += track2->get_type().get_path_length(path);
1305 bool ok = (track2!=from && diversion.has_track(*track2));
1307 track2 = track2.next(path);
1315 if(!advance_route(route, *track2))
1319 // Must end up at the same place through both routes
1323 return diversion_len<route_len*1.2;
1327 Train::RouteRef::RouteRef(const Route *r, unsigned d):
1333 Train::RealSpeed::RealSpeed():
1338 void Train::RealSpeed::add(float s, float w)
1340 speed = (speed*weight+s*w)/(weight+w);
1341 weight = min(weight+w, 300.0f);
1345 Train::Loader::Loader(Train &t):
1346 DataFile::BasicLoader<Train>(t),
1350 add("block", &Loader::block);
1351 add("block_hint", &Loader::block_hint);
1352 add("name", &Loader::name);
1353 add("priority", &Train::priority);
1354 add("real_speed", &Loader::real_speed);
1355 add("route", &Loader::route);
1356 add("timetable", &Loader::timetable);
1357 add("vehicle", &Loader::vehicle);
1360 void Train::Loader::finish()
1362 if(!obj.blocks.empty())
1364 TrackIter track = obj.blocks.front().track_iter();
1365 float offset = 2*obj.layout.get_catalogue().get_scale();
1366 obj.vehicles.back()->place(*track, track.entry(), offset, Vehicle::BACK_BUFFER);
1368 obj.set_status("Stopped");
1372 void Train::Loader::block(unsigned id)
1380 blk = &obj.layout.get_block(id);
1382 catch(const KeyError &)
1384 blocks_valid = false;
1390 entry = blk->get_endpoint_by_link(*prev_block);
1395 obj.blocks.push_back(BlockIter(blk, entry));
1397 if(blk->get_sensor_id())
1398 obj.layout.get_driver().set_sensor(blk->get_sensor_id(), true);
1403 void Train::Loader::block_hint(unsigned id)
1407 prev_block = &obj.layout.get_block(id);
1409 catch(const KeyError &)
1411 blocks_valid = false;
1415 void Train::Loader::name(const string &n)
1420 void Train::Loader::real_speed(unsigned i, float speed, float weight)
1422 if(i>=obj.real_speed.size())
1424 obj.real_speed[i].speed = speed;
1425 obj.real_speed[i].weight = weight;
1428 void Train::Loader::route(const string &n)
1430 obj.set_route(&obj.layout.get_route(n));
1433 void Train::Loader::timetable()
1436 throw InvalidState("A timetable has already been loaded");
1438 obj.timetable = new Timetable(obj);
1439 load_sub(*obj.timetable);
1442 void Train::Loader::vehicle(ArticleNumber art_nr)
1444 const VehicleType &vtype = obj.layout.get_catalogue().get_vehicle(art_nr);
1445 Vehicle *veh = new Vehicle(obj.layout, vtype);
1446 obj.vehicles.back()->attach_back(*veh);
1447 obj.vehicles.push_back(veh);