3 This file is part of the MSP Märklin suite
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"
34 SetFlag(bool &f): flag(f) { flag = true; }
35 ~SetFlag() { flag = false; }
43 Train::Train(Layout &l, const VehicleType &t, unsigned a):
52 controller(new AIControl(*this, new SimpleController)),
56 speed_changing(false),
64 accurate_position(false),
67 if(!loco_type.is_locomotive())
68 throw InvalidParameterValue("Initial vehicle must be a locomotive");
70 vehicles.push_back(new Vehicle(layout, loco_type));
72 layout.add_train(*this);
74 layout.get_driver().add_loco(address);
75 layout.get_driver().signal_loco_speed.connect(sigc::mem_fun(this, &Train::loco_speed_event));
76 layout.get_driver().signal_loco_function.connect(sigc::mem_fun(this, &Train::loco_func_event));
78 layout.signal_block_reserved.connect(sigc::mem_fun(this, &Train::block_reserved));
79 layout.get_driver().signal_sensor.connect(sigc::mem_fun(this, &Train::sensor_event));
80 layout.get_driver().signal_turnout.connect(sigc::mem_fun(this, &Train::turnout_event));
82 layout.get_driver().signal_halt.connect(sigc::mem_fun(this, &Train::halt_event));
84 controller->signal_control_changed.connect(sigc::mem_fun(this, &Train::control_changed));
91 for(vector<Vehicle *>::iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
93 layout.remove_train(*this);
96 void Train::set_name(const string &n)
100 signal_name_changed.emit(name);
103 void Train::set_priority(int p)
108 void Train::yield_to(const Train &t)
113 void Train::add_vehicle(const VehicleType &vt)
115 Vehicle *veh = new Vehicle(layout, vt);
116 vehicles.back()->attach_back(*veh);
117 vehicles.push_back(veh);
120 void Train::remove_vehicle(unsigned i)
122 if(i>=vehicles.size())
123 throw InvalidParameterValue("Vehicle index out of range");
125 throw InvalidParameterValue("Can't remove the locomotive");
127 vehicles.erase(vehicles.begin()+i);
128 if(i<vehicles.size())
129 vehicles[i-1]->attach_back(*vehicles[i]);
132 unsigned Train::get_n_vehicles() const
134 return vehicles.size();
137 Vehicle &Train::get_vehicle(unsigned i)
139 if(i>=vehicles.size())
140 throw InvalidParameterValue("Vehicle index out of range");
144 const Vehicle &Train::get_vehicle(unsigned i) const
146 if(i>=vehicles.size())
147 throw InvalidParameterValue("Vehicle index out of range");
151 void Train::set_control(const string &n, float v)
153 controller->set_control(n, v);
156 void Train::set_active(bool a)
160 if(!a && controller->get_speed())
161 throw InvalidState("Can't deactivate while moving");
166 stop_timeout = Time::TimeStamp();
171 stop_timeout = Time::now()+2*Time::sec;
172 set_status("Stopped");
176 void Train::set_function(unsigned func, bool state)
178 if(!loco_type.get_functions().count(func))
179 throw InvalidParameterValue("Invalid function");
181 layout.get_driver().set_loco_function(address, func, state);
183 layout.get_driver().set_loco_function(address+1, func-4, state);
186 float Train::get_control(const string &ctrl) const
188 return controller->get_control(ctrl).value;
191 float Train::get_speed() const
193 return controller->get_speed();
196 bool Train::get_function(unsigned func) const
198 return (functions>>func)&1;
201 void Train::set_timetable(Timetable *tt)
207 bool Train::set_route(const Route *r)
209 free_noncritical_blocks();
212 if(r && !cur_blocks.empty())
214 TrackIter first = cur_blocks.front().track_iter();
215 TrackIter next = (rsv_blocks.empty() ? cur_blocks : rsv_blocks).back().next().track_iter();
216 if(!r->has_track(*next))
218 lead = Route::find(next, *r);
221 create_lead_route(lead, lead);
222 routes.push_front(lead);
224 else if(!r->has_track(*first))
225 lead = create_lead_route(0, r);
230 routes.push_back(lead);
233 end_of_route = false;
237 signal_route_changed.emit(get_route());
242 bool Train::go_to(Track &to)
244 for(BlockList::const_iterator i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
245 if((*i)->has_track(to))
247 signal_arrived.emit();
251 free_noncritical_blocks();
253 TrackIter next = (rsv_blocks.empty() ? cur_blocks : rsv_blocks).back().next().track_iter();
255 Route *route = Route::find(next, to);
258 create_lead_route(route, route);
259 return set_route(route);
262 bool Train::divert(Track &from)
264 if(!from.get_turnout_id())
265 throw InvalidParameterValue("Can't divert from a non-turnout");
271 list<RouteRef>::iterator route = routes.begin();
273 // Follow our routes to find out where we're entering the turnout
274 for(TrackLoopIter track = cur_blocks.back().track_iter();;)
276 if(!advance_route(route, *track))
281 Block &block = track->get_block();
282 if(block.get_train()==this && !free_block(block))
285 int route_path = route->route->get_turnout(from.get_turnout_id());
287 // Check that more than one path is available
288 unsigned ep_paths = track->get_type().get_endpoints()[track.entry()].paths;
289 if(!(ep_paths&(ep_paths-1)))
292 // Choose some other path
293 for(int i=0; ep_paths>>i; ++i)
294 if((ep_paths&(1<<i)) && i!=route_path)
300 entry = track.entry();
304 unsigned tid = track->get_turnout_id();
305 track = track.next(tid ? route->route->get_turnout(tid) : 0);
307 if(!track || track.looped())
311 TrackIter track = TrackIter(&from, entry).next(path);
316 for(list<RouteRef>::iterator i=routes.begin(); i!=routes.end(); ++i)
317 tracks.insert(i->route->get_tracks().begin(), i->route->get_tracks().end());
318 RefPtr<Route> diversion = Route::find(track, tracks);
322 diversion->set_name("Diversion");
323 diversion->add_track(from);
324 diversion->set_turnout(from.get_turnout_id(), path);
326 if(!is_valid_diversion(*diversion, TrackIter(&from, entry)))
329 // Follow the diversion route until we get back to the original route
330 list<RouteRef>::iterator end = routes.end();
333 for(list<RouteRef>::iterator i=route; (end==routes.end() && i!=routes.end()); ++i)
334 if(i->route->has_track(*track))
337 if(end!=routes.end())
339 else if(!diversion->has_track(*track))
340 throw LogicError("Pathfinder returned a bad route");
342 unsigned tid = track->get_turnout_id();
343 track = track.next(tid ? diversion->get_turnout(tid) : 0);
347 // We are rejoining the same route we diverted from, duplicate it
348 routes.insert(end, *route);
352 routes.erase(route, end);
354 routes.insert(end, RouteRef(diversion.release(), from.get_turnout_id()));
359 const Route *Train::get_route() const
363 return routes.front().route;
366 void Train::place(Block &block, unsigned entry)
368 if(controller->get_speed())
369 throw InvalidState("Must be stopped before placing");
371 release_blocks(rsv_blocks);
372 release_blocks(cur_blocks);
375 accurate_position = false;
377 if(!block.reserve(this))
379 set_status("Unplaced");
383 cur_blocks.push_back(BlockIter(&block, entry));
386 TrackIter track = BlockIter(&block, entry).reverse().track_iter();
387 vehicles.front()->place(*track, track.entry(), 0, Vehicle::FRONT_BUFFER);
391 const Block::Endpoint &bep = block.get_endpoints()[entry];
392 vehicles.back()->place(*bep.track, bep.track_ep, 0, Vehicle::BACK_BUFFER);
396 void Train::unplace()
398 if(controller->get_speed())
399 throw InvalidState("Must be stopped before unplacing");
401 release_blocks(rsv_blocks);
402 release_blocks(cur_blocks);
405 accurate_position = false;
407 for(vector<Vehicle *>::iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
410 set_status("Unplaced");
413 bool Train::free_block(Block &block)
415 float margin = 10*layout.get_catalogue().get_scale();
416 if(get_reserved_distance_until(&block, false)<controller->get_braking_distance()*1.3+margin)
420 for(BlockList::iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
422 if(i->block()==&block)
426 release_blocks(rsv_blocks, i, rsv_blocks.end());
429 else if((*i)->get_sensor_id())
436 void Train::free_noncritical_blocks()
438 if(cur_blocks.empty() || rsv_blocks.empty())
441 if(controller->get_speed()==0)
443 release_blocks(rsv_blocks);
447 float margin = 10*layout.get_catalogue().get_scale();
448 float min_dist = controller->get_braking_distance()*1.3+margin;
450 Vehicle &veh = *(reverse ? vehicles.back() : vehicles.front());
452 TrackIter track(veh.get_track(), veh.get_entry());
453 BlockList::iterator block = cur_blocks.begin();
455 while(block!=rsv_blocks.end() && !(*block)->has_track(*track))
458 if(block==cur_blocks.end())
460 block = rsv_blocks.begin();
465 float dist = veh.get_offset();
469 dist = track->get_type().get_path_length(track->get_active_path())-dist;
470 dist -= veh.get_type().get_length()/2;
475 track = track.next();
477 if(!(*block)->has_track(*track))
480 if(block==cur_blocks.end())
482 block = rsv_blocks.begin();
485 if(block==rsv_blocks.end())
488 if(dist>min_dist && nsens>0)
490 release_blocks(rsv_blocks, block, rsv_blocks.end());
494 if(in_rsv && (*block)->get_sensor_id())
498 dist += track->get_type().get_path_length(track->get_active_path());
502 int Train::get_entry_to_block(Block &block) const
504 for(BlockList::const_iterator i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
505 if(i->block()==&block)
507 for(BlockList::const_iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
508 if(i->block()==&block)
513 float Train::get_reserved_distance() const
515 return get_reserved_distance_until(0, false);
518 void Train::tick(const Time::TimeStamp &t, const Time::TimeDelta &dt)
520 if(!active && stop_timeout && t>=stop_timeout)
522 release_blocks(rsv_blocks);
523 end_of_route = false;
524 stop_timeout = Time::TimeStamp();
527 Driver &driver = layout.get_driver();
531 controller->tick(dt);
532 float speed = controller->get_speed();
533 unsigned speed_notch = find_speed(speed);
535 if(controller->get_reverse()!=reverse)
537 reverse = controller->get_reverse();
538 driver.set_loco_reverse(address, reverse);
540 release_blocks(rsv_blocks);
541 reverse_blocks(cur_blocks);
545 if(speed_notch!=current_speed && !speed_changing && !driver.is_halted() && driver.get_power())
547 speed_changing = true;
548 driver.set_loco_speed(address, speed_notch);
553 set_status(format("Traveling %d kmh", get_travel_speed()));
555 set_status("Waiting");
563 Vehicle &vehicle = *(reverse ? vehicles.back() : vehicles.front());
564 Track *track = vehicle.get_track();
567 for(BlockList::const_iterator i=cur_blocks.begin(); (!ok && i!=cur_blocks.end()); ++i)
568 ok = (*i)->has_track(*track);
570 float d = get_real_speed(current_speed)*(dt/Time::sec);
573 SetFlag setf(advancing);
574 vehicle.advance(reverse ? -d : d);
576 else if(accurate_position)
579 if(overshoot_dist>40*layout.get_catalogue().get_scale())
581 layout.emergency(name+" has not arrived at sensor");
582 accurate_position = false;
586 else if(end_of_route && rsv_blocks.empty())
589 signal_arrived.emit();
593 if(!cur_blocks.empty() && !cur_blocks.front()->get_sensor_id())
595 float dist = get_reserved_distance_until(&*cur_blocks.front(), true);
597 if(dist>10*layout.get_catalogue().get_scale())
599 cur_blocks.front()->reserve(0);
600 cur_blocks.pop_front();
605 void Train::save(list<DataFile::Statement> &st) const
607 st.push_back((DataFile::Statement("name"), name));
609 st.push_back((DataFile::Statement("priority"), priority));
611 for(vector<Vehicle *>::const_iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
612 if(i!=vehicles.begin())
613 st.push_back((DataFile::Statement("vehicle"), (*i)->get_type().get_article_number()));
615 for(unsigned i=0; i<=14; ++i)
616 if(real_speed[i].weight)
617 st.push_back((DataFile::Statement("real_speed"), i, real_speed[i].speed, real_speed[i].weight));
619 if(!cur_blocks.empty())
621 BlockList blocks = cur_blocks;
623 reverse_blocks(blocks);
625 BlockIter prev = blocks.front().flip();
626 st.push_back((DataFile::Statement("block_hint"), prev->get_id()));
628 for(BlockList::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
629 st.push_back((DataFile::Statement("block"), (*i)->get_id()));
634 list<RouteRef>::const_iterator i = routes.begin();
635 for(; (i!=routes.end() && i->route->is_temporary()); ++i) ;
637 st.push_back((DataFile::Statement("route"), i->route->get_name()));
642 DataFile::Statement ss("timetable");
643 timetable->save(ss.sub);
648 void Train::control_changed(const Controller::Control &ctrl)
650 signal_control_changed.emit(ctrl.name, ctrl.value);
653 void Train::loco_speed_event(unsigned addr, unsigned speed, bool)
657 current_speed = speed;
658 speed_changing = false;
663 void Train::loco_func_event(unsigned addr, unsigned func, bool state)
665 if(addr==address || (addr==address+1 && loco_type.get_max_function()>4))
670 functions |= 1<<func;
672 functions &= ~(1<<func);
674 signal_function_changed.emit(func, state);
678 void Train::sensor_event(unsigned addr, bool state)
682 // Find the first sensor block from our reserved blocks that isn't this sensor
683 BlockList::iterator i;
685 for(i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
686 if((*i)->get_sensor_id())
688 if((*i)->get_sensor_id()!=addr)
701 if(result==1 && i!=rsv_blocks.begin())
703 // Compute speed and update related state
704 float travel_time_secs = (Time::now()-last_entry_time)/Time::sec;
710 RealSpeed &rs = real_speed[current_speed];
711 rs.add(travel_dist/travel_time_secs, travel_time_secs);
713 set_status(format("Traveling %d kmh", get_travel_speed()));
717 for(BlockList::iterator j=rsv_blocks.begin(); j!=i; ++j)
719 travel_dist += (*j)->get_path_length(j->entry());
721 if((*j)->get_sensor_id()==addr && !advancing)
723 TrackIter track = j->track_iter();
726 track = track.flip();
727 vehicles.back()->place(*track, track.entry(), 0, Vehicle::BACK_AXLE);
730 vehicles.front()->place(*track, track.entry(), 0, Vehicle::FRONT_AXLE);
733 last_entry_time = Time::now();
735 accurate_position = true;
738 // Check if we've reached the next route
741 const set<Track *> &rtracks = (++routes.begin())->route->get_tracks();
742 for(BlockList::iterator j=rsv_blocks.begin(); j!=i; ++j)
743 if(rtracks.count((*j)->get_endpoints()[j->entry()].track))
747 signal_route_changed.emit(routes.front().route);
752 // Move blocks up to the next sensor to our current blocks
753 cur_blocks.splice(cur_blocks.end(), rsv_blocks, rsv_blocks.begin(), i);
755 // Try to get more blocks if we're moving
760 layout.emergency("Sensor for "+name+" triggered out of order");
764 const Vehicle &veh = *(reverse ? vehicles.front() : vehicles.back());
766 // Find the first sensor in our current blocks that's still active
767 BlockList::iterator end = cur_blocks.begin();
768 for(BlockList::iterator i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
770 if((*i)->has_track(*veh.get_track()))
772 if((*i)->get_sensor_id())
774 if(layout.get_driver().get_sensor((*i)->get_sensor_id()))
784 if(end!=cur_blocks.begin() && end!=cur_blocks.end())
785 // Free blocks up to the last inactive sensor
786 release_blocks(cur_blocks, cur_blocks.begin(), end);
790 void Train::turnout_event(unsigned addr, bool)
792 if(pending_block && (!pending_block->get_train() || pending_block->get_train()==this))
794 unsigned pending_addr = pending_block->get_turnout_id();
795 bool double_addr = (*pending_block->get_tracks().begin())->get_type().is_double_address();
796 if(addr==pending_addr || (double_addr && addr==pending_addr+1))
806 void Train::halt_event(bool h)
809 accurate_position = false;
812 void Train::block_reserved(const Block &block, const Train *train)
814 if(&block==pending_block && !train && !reserving)
818 unsigned Train::reserve_more()
824 if(!rsv_blocks.empty())
825 start = rsv_blocks.back();
826 else if(!cur_blocks.empty())
827 start = cur_blocks.back();
833 // See how many sensor blocks and how much track we already have
836 for(BlockList::const_iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
838 if((*i)->get_sensor_id())
841 dist += (*i)->get_path_length(i->entry());
847 list<RouteRef>::iterator cur_route = routes.begin();
848 advance_route(cur_route, *start.track_iter());
850 float approach_margin = 50*layout.get_catalogue().get_scale();
851 float min_dist = controller->get_braking_distance()*1.3+approach_margin*2;
853 BlockIter block = start;
854 BlockIter good = start;
855 Track *divert_track = 0;
856 bool try_divert = false;
857 unsigned good_sens = nsens;
858 float good_dist = dist;
859 Train *blocking_train = 0;
860 BlockList contested_blocks;
862 SetFlag setf(reserving);
864 while(good_sens<3 || good_dist<min_dist || !contested_blocks.empty())
866 BlockIter last = block;
867 block = block.next(cur_route!=routes.end() ? cur_route->route : 0);
871 TrackIter track = block.track_iter();
873 if(cur_route!=routes.end())
875 if(!advance_route(cur_route, *track))
877 // Keep the blocks if we arrived at the end of the route
888 else if(!routes.empty() && routes.front().route->has_track(*track))
889 cur_route = routes.begin();
891 if(block->get_endpoints().size()<2)
904 if(block->get_train()!=blocking_train)
906 if(blocking_train->free_block(*contested_blocks.back()))
908 // Roll back and start actually reserving the blocks
909 block = rsv_blocks.back();
910 cur_route = routes.begin();
911 advance_route(cur_route, *block.track_iter().track());
912 if(blocking_train->get_priority()==priority)
913 blocking_train->yield_to(*this);
919 yield_to(*blocking_train);
920 pending_block = contested_blocks.front().block();
921 try_divert = divert_track;
927 contested_blocks.push_back(block);
932 bool reserved = block->reserve(this);
935 /* We've found another train. If it wants to exit the block from the
936 same endpoint we're trying to enter from or the other way around,
937 treat it as coming towards us. Otherwise treat it as going in the
939 Train *other_train = block->get_train();
940 int other_entry = other_train->get_entry_to_block(*block);
942 throw LogicError("Block reservation inconsistency");
944 unsigned exit = block.reverse().entry();
945 unsigned other_exit = BlockIter(block.block(), other_entry).reverse().entry();
946 bool entry_conflict = (block.entry()==other_exit);
947 bool exit_conflict = (exit==static_cast<unsigned>(other_entry));
948 if(!entry_conflict && !last->get_turnout_id())
950 /* The other train is not coming to the blocks we're holding, so we
957 int other_prio = other_train->get_priority();
959 if(!entry_conflict && !exit_conflict && other_prio<priority)
961 /* Ask a lesser priority train going to the same direction to free
963 if(other_train->free_block(*block))
964 reserved = block->reserve(this);
966 else if(other_train!=yielding_to && (other_prio<priority || (other_prio==priority && entry_conflict)))
968 /* A lesser priority train is coming at us, we must ask it to free
969 enough blocks to get clear of it to avoid a potential deadlock */
970 blocking_train = other_train;
971 contested_blocks.clear();
972 contested_blocks.push_back(block);
975 else if(divert_track && (entry_conflict || exit_conflict))
976 // We are blocked, but there's a diversion possibility
981 pending_block = &*block;
986 if(block->get_turnout_id())
988 const TrackType::Endpoint &track_ep = track->get_type().get_endpoints()[track.entry()];
989 bool multiple_paths = (track_ep.paths&(track_ep.paths-1));
991 if(multiple_paths || !last->get_turnout_id())
993 /* We can keep the blocks reserved so far if we are facing the
994 points or if there was no turnout immediately before this one.
995 With multiple successive turnouts (as is common in crossovers) it's
996 best to hold at one we can divert from. */
1002 // Figure out what path we'd like to take on the turnout
1004 for(list<RouteRef>::iterator i=cur_route; (path<0 && i!=routes.end()); ++i)
1005 path = i->route->get_turnout(block->get_turnout_id());
1007 path = track->get_active_path();
1008 if(!(track_ep.paths&(1<<path)))
1010 for(unsigned i=0; track_ep.paths>>i; ++i)
1011 if(track_ep.paths&(1<<i))
1015 if(path!=static_cast<int>(track->get_active_path()))
1017 // The turnout is set to wrong path - switch and wait for it
1018 pending_block = &*block;
1019 track->set_active_path(path);
1027 if(multiple_paths && cur_route!=routes.end() && cur_route->diversion!=block->get_turnout_id())
1028 /* There's multiple paths to be taken and we are on a route - take
1029 note of the diversion possibility */
1030 divert_track = &*track;
1033 if(!contested_blocks.empty() && contested_blocks.front()==block)
1034 contested_blocks.pop_front();
1036 rsv_blocks.push_back(block);
1037 if(block->get_sensor_id())
1040 dist += block->get_path_length(block.entry());
1043 // Unreserve blocks that were not good
1044 while(!rsv_blocks.empty() && rsv_blocks.back()!=good)
1046 rsv_blocks.back()->reserve(0);
1047 rsv_blocks.pop_back();
1050 if(!rsv_blocks.empty() && rsv_blocks.back()!=start)
1051 // We got some new blocks, so no longer need to yield
1054 // Make any sensorless blocks at the beginning immediately current
1055 BlockList::iterator i;
1056 for(i=rsv_blocks.begin(); (i!=rsv_blocks.end() && !(*i)->get_sensor_id()); ++i) ;
1057 if(i!=rsv_blocks.begin())
1058 cur_blocks.splice(cur_blocks.end(), rsv_blocks, rsv_blocks.begin(), i);
1060 if(try_divert && divert(*divert_track))
1061 return reserve_more();
1066 float Train::get_reserved_distance_until(const Block *until_block, bool back) const
1068 if(cur_blocks.empty())
1071 Vehicle &veh = *(reverse!=back ? vehicles.back() : vehicles.front());
1072 const VehicleType &vtype = veh.get_type();
1074 TrackIter track(veh.get_track(), veh.get_entry());
1078 BlockList::const_iterator block = cur_blocks.begin();
1079 while(block!=rsv_blocks.end() && !(*block)->has_track(*track))
1082 if(block==cur_blocks.end())
1086 block = rsv_blocks.begin();
1089 if(block==rsv_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==cur_blocks.begin())
1116 if(block==cur_blocks.end())
1117 block = rsv_blocks.begin();
1118 if(block==rsv_blocks.end())
1122 if(&**block==until_block)
1126 result += track->get_type().get_path_length(track->get_active_path());
1132 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<14; ++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(float real) const
1164 if(real<=real_speed[0].speed)
1170 for(unsigned i=0; (!high && i<=14); ++i)
1171 if(real_speed[i].weight)
1174 if(real_speed[i].speed<real)
1188 return min(min(static_cast<unsigned>(low*real/real_speed[low].speed), 14U), last+3);
1191 float f = (real-real_speed[low].speed)/(real_speed[high].speed-real_speed[low].speed);
1192 return static_cast<unsigned>(low*(1-f)+high*f+0.5);
1195 float Train::get_travel_speed() const
1197 float speed = get_real_speed(current_speed);
1198 float scale = layout.get_catalogue().get_scale();
1199 return static_cast<int>(round(speed/scale*3.6/5))*5;
1202 void Train::set_status(const string &s)
1205 signal_status_changed.emit(s);
1208 void Train::release_blocks(BlockList &blocks)
1210 release_blocks(blocks, blocks.begin(), blocks.end());
1213 void Train::release_blocks(BlockList &blocks, BlockList::iterator begin, BlockList::iterator end)
1217 Block &block = **begin;
1218 blocks.erase(begin++);
1223 void Train::reverse_blocks(BlockList &blocks) const
1226 for(BlockList::iterator i=blocks.begin(); i!=blocks.end(); ++i)
1230 bool Train::advance_route(list<RouteRef>::iterator &iter, Track &track)
1232 while(iter!=routes.end() && !iter->route->has_track(track))
1234 if(iter==routes.end())
1237 list<RouteRef>::iterator next = iter;
1239 if(next!=routes.end() && next->diversion && next->route->has_track(track))
1245 Route *Train::create_lead_route(Route *lead, const Route *target)
1249 lead = new Route(layout);
1250 lead->set_name("Lead");
1251 lead->set_temporary(true);
1254 set<Track *> tracks;
1255 for(BlockList::iterator i=cur_blocks.begin(); i!=rsv_blocks.end(); )
1257 const set<Track *> &btracks = (*i)->get_tracks();
1258 for(set<Track *>::const_iterator j=btracks.begin(); j!=btracks.end(); ++j)
1259 if(!target || !target->has_track(**j))
1262 if(++i==cur_blocks.end())
1263 i = rsv_blocks.begin();
1266 lead->add_tracks(tracks);
1271 bool Train::is_valid_diversion(const Route &diversion, const TrackIter &from)
1273 float diversion_len = 0;
1274 TrackLoopIter track1 = from;
1275 while(diversion.has_track(*track1))
1277 unsigned tid = track1->get_turnout_id();
1278 unsigned path = (tid ? diversion.get_turnout(tid) : 0);
1279 diversion_len += track1->get_type().get_path_length(path);
1281 track1 = track1.next(path);
1287 list<RouteRef>::iterator route = routes.begin();
1288 if(!advance_route(route, *from))
1291 float route_len = 0;
1292 TrackLoopIter track2 = from;
1295 unsigned tid = track2->get_turnout_id();
1296 unsigned path = (tid ? route->route->get_turnout(tid) : 0);
1297 route_len += track2->get_type().get_path_length(path);
1299 bool ok = (track2!=from && diversion.has_track(*track2));
1301 track2 = track2.next(path);
1309 if(!advance_route(route, *track2))
1313 // Must end up at the same place through both routes
1317 return diversion_len<route_len*1.2;
1321 Train::RouteRef::RouteRef(const Route *r, unsigned d):
1327 Train::RealSpeed::RealSpeed():
1332 void Train::RealSpeed::add(float s, float w)
1334 speed = (speed*weight+s*w)/(weight+w);
1335 weight = min(weight+w, 300.0f);
1339 Train::Loader::Loader(Train &t):
1340 DataFile::BasicLoader<Train>(t),
1344 add("block", &Loader::block);
1345 add("block_hint", &Loader::block_hint);
1346 add("name", &Loader::name);
1347 add("priority", &Train::priority);
1348 add("real_speed", &Loader::real_speed);
1349 add("route", &Loader::route);
1350 add("timetable", &Loader::timetable);
1351 add("vehicle", &Loader::vehicle);
1354 void Train::Loader::finish()
1356 if(!obj.cur_blocks.empty())
1358 TrackIter track = obj.cur_blocks.front().track_iter();
1359 float offset = 2*obj.layout.get_catalogue().get_scale();
1360 obj.vehicles.back()->place(*track, track.entry(), offset, Vehicle::BACK_BUFFER);
1362 obj.set_status("Stopped");
1366 void Train::Loader::block(unsigned id)
1374 blk = &obj.layout.get_block(id);
1376 catch(const KeyError &)
1378 blocks_valid = false;
1384 entry = blk->get_endpoint_by_link(*prev_block);
1389 obj.cur_blocks.push_back(BlockIter(blk, entry));
1391 if(blk->get_sensor_id())
1392 obj.layout.get_driver().set_sensor(blk->get_sensor_id(), true);
1397 void Train::Loader::block_hint(unsigned id)
1401 prev_block = &obj.layout.get_block(id);
1403 catch(const KeyError &)
1405 blocks_valid = false;
1409 void Train::Loader::name(const string &n)
1414 void Train::Loader::real_speed(unsigned i, float speed, float weight)
1416 obj.real_speed[i].speed = speed;
1417 obj.real_speed[i].weight = weight;
1420 void Train::Loader::route(const string &n)
1422 obj.set_route(&obj.layout.get_route(n));
1425 void Train::Loader::timetable()
1428 throw InvalidState("A timetable has already been loaded");
1430 obj.timetable = new Timetable(obj);
1431 load_sub(*obj.timetable);
1434 void Train::Loader::vehicle(ArticleNumber art_nr)
1436 const VehicleType &vtype = obj.layout.get_catalogue().get_vehicle(art_nr);
1437 Vehicle *veh = new Vehicle(obj.layout, vtype);
1438 obj.vehicles.back()->attach_back(*veh);
1439 obj.vehicles.push_back(veh);
1442 } // namespace Marklin