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 track = track.next(route->route->get_path(*track));
306 if(!track || track.looped())
310 TrackIter track = TrackIter(&from, entry).next(path);
315 for(list<RouteRef>::iterator i=routes.begin(); i!=routes.end(); ++i)
316 tracks.insert(i->route->get_tracks().begin(), i->route->get_tracks().end());
317 RefPtr<Route> diversion = Route::find(track, tracks);
321 diversion->set_name("Diversion");
322 diversion->add_track(from);
323 diversion->set_turnout(from.get_turnout_id(), path);
325 if(!is_valid_diversion(*diversion, TrackIter(&from, entry)))
328 // Follow the diversion route until we get back to the original route
329 list<RouteRef>::iterator end = routes.end();
332 for(list<RouteRef>::iterator i=route; (end==routes.end() && i!=routes.end()); ++i)
333 if(i->route->has_track(*track))
336 if(end!=routes.end())
338 else if(!diversion->has_track(*track))
339 throw LogicError("Pathfinder returned a bad route");
341 track = track.next(diversion->get_path(*track));
345 // We are rejoining the same route we diverted from, duplicate it
346 routes.insert(end, *route);
350 routes.erase(route, end);
352 routes.insert(end, RouteRef(diversion.release(), from.get_turnout_id()));
357 const Route *Train::get_route() const
361 return routes.front().route;
364 void Train::place(Block &block, unsigned entry)
366 if(controller->get_speed())
367 throw InvalidState("Must be stopped before placing");
369 release_blocks(rsv_blocks);
370 release_blocks(cur_blocks);
373 accurate_position = false;
375 if(!block.reserve(this))
377 set_status("Unplaced");
381 cur_blocks.push_back(BlockIter(&block, entry));
384 TrackIter track = BlockIter(&block, entry).reverse().track_iter();
385 vehicles.front()->place(*track, track.entry(), 0, Vehicle::FRONT_BUFFER);
389 const Block::Endpoint &bep = block.get_endpoints()[entry];
390 vehicles.back()->place(*bep.track, bep.track_ep, 0, Vehicle::BACK_BUFFER);
394 void Train::unplace()
396 if(controller->get_speed())
397 throw InvalidState("Must be stopped before unplacing");
399 release_blocks(rsv_blocks);
400 release_blocks(cur_blocks);
403 accurate_position = false;
405 for(vector<Vehicle *>::iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
408 set_status("Unplaced");
411 bool Train::free_block(Block &block)
413 float margin = 10*layout.get_catalogue().get_scale();
414 if(get_reserved_distance_until(&block, false)<controller->get_braking_distance()*1.3+margin)
418 for(BlockList::iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
420 if(i->block()==&block)
424 release_blocks(rsv_blocks, i, rsv_blocks.end());
427 else if((*i)->get_sensor_id())
434 void Train::free_noncritical_blocks()
436 if(cur_blocks.empty() || rsv_blocks.empty())
439 if(controller->get_speed()==0)
441 release_blocks(rsv_blocks);
445 float margin = 10*layout.get_catalogue().get_scale();
446 float min_dist = controller->get_braking_distance()*1.3+margin;
448 Vehicle &veh = *(reverse ? vehicles.back() : vehicles.front());
450 TrackIter track(veh.get_track(), veh.get_entry());
451 BlockList::iterator block = cur_blocks.begin();
453 while(block!=rsv_blocks.end() && !(*block)->has_track(*track))
456 if(block==cur_blocks.end())
458 block = rsv_blocks.begin();
463 float dist = veh.get_offset();
467 dist = track->get_type().get_path_length(track->get_active_path())-dist;
468 dist -= veh.get_type().get_length()/2;
473 track = track.next();
475 if(!(*block)->has_track(*track))
478 if(block==cur_blocks.end())
480 block = rsv_blocks.begin();
483 if(block==rsv_blocks.end())
486 if(dist>min_dist && nsens>0)
488 release_blocks(rsv_blocks, block, rsv_blocks.end());
492 if(in_rsv && (*block)->get_sensor_id())
496 dist += track->get_type().get_path_length(track->get_active_path());
500 int Train::get_entry_to_block(Block &block) const
502 for(BlockList::const_iterator i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
503 if(i->block()==&block)
505 for(BlockList::const_iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
506 if(i->block()==&block)
511 float Train::get_reserved_distance() const
513 return get_reserved_distance_until(0, false);
516 void Train::tick(const Time::TimeStamp &t, const Time::TimeDelta &dt)
518 if(!active && stop_timeout && t>=stop_timeout)
520 release_blocks(rsv_blocks);
521 end_of_route = false;
522 stop_timeout = Time::TimeStamp();
525 Driver &driver = layout.get_driver();
529 controller->tick(dt);
530 float speed = controller->get_speed();
531 unsigned speed_notch = find_speed(speed);
533 if(controller->get_reverse()!=reverse)
535 reverse = controller->get_reverse();
536 driver.set_loco_reverse(address, reverse);
538 release_blocks(rsv_blocks);
539 reverse_blocks(cur_blocks);
543 if(speed_notch!=current_speed && !speed_changing && !driver.is_halted() && driver.get_power())
545 speed_changing = true;
546 driver.set_loco_speed(address, speed_notch);
551 set_status(format("Traveling %d kmh", get_travel_speed()));
553 set_status("Waiting");
561 Vehicle &vehicle = *(reverse ? vehicles.back() : vehicles.front());
562 Track *track = vehicle.get_track();
565 for(BlockList::const_iterator i=cur_blocks.begin(); (!ok && i!=cur_blocks.end()); ++i)
566 ok = (*i)->has_track(*track);
568 float d = get_real_speed(current_speed)*(dt/Time::sec);
571 SetFlag setf(advancing);
572 vehicle.advance(reverse ? -d : d);
574 else if(accurate_position)
577 if(overshoot_dist>40*layout.get_catalogue().get_scale())
579 layout.emergency(name+" has not arrived at sensor");
580 accurate_position = false;
584 else if(end_of_route && rsv_blocks.empty())
587 signal_arrived.emit();
591 if(!cur_blocks.empty() && !cur_blocks.front()->get_sensor_id())
593 float dist = get_reserved_distance_until(&*cur_blocks.front(), true);
595 if(dist>10*layout.get_catalogue().get_scale())
597 cur_blocks.front()->reserve(0);
598 cur_blocks.pop_front();
603 void Train::save(list<DataFile::Statement> &st) const
605 st.push_back((DataFile::Statement("name"), name));
607 st.push_back((DataFile::Statement("priority"), priority));
609 for(vector<Vehicle *>::const_iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
610 if(i!=vehicles.begin())
611 st.push_back((DataFile::Statement("vehicle"), (*i)->get_type().get_article_number()));
613 for(unsigned i=0; i<=14; ++i)
614 if(real_speed[i].weight)
615 st.push_back((DataFile::Statement("real_speed"), i, real_speed[i].speed, real_speed[i].weight));
617 if(!cur_blocks.empty())
619 BlockList blocks = cur_blocks;
621 reverse_blocks(blocks);
623 BlockIter prev = blocks.front().flip();
624 st.push_back((DataFile::Statement("block_hint"), prev->get_id()));
626 for(BlockList::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
627 st.push_back((DataFile::Statement("block"), (*i)->get_id()));
632 list<RouteRef>::const_iterator i = routes.begin();
633 for(; (i!=routes.end() && i->route->is_temporary()); ++i) ;
635 st.push_back((DataFile::Statement("route"), i->route->get_name()));
640 DataFile::Statement ss("timetable");
641 timetable->save(ss.sub);
646 void Train::control_changed(const Controller::Control &ctrl)
648 signal_control_changed.emit(ctrl.name, ctrl.value);
651 void Train::loco_speed_event(unsigned addr, unsigned speed, bool)
655 current_speed = speed;
656 speed_changing = false;
661 void Train::loco_func_event(unsigned addr, unsigned func, bool state)
663 if(addr==address || (addr==address+1 && loco_type.get_max_function()>4))
668 functions |= 1<<func;
670 functions &= ~(1<<func);
672 signal_function_changed.emit(func, state);
676 void Train::sensor_event(unsigned addr, bool state)
680 // Find the first sensor block from our reserved blocks that isn't this sensor
681 BlockList::iterator i;
683 for(i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
684 if((*i)->get_sensor_id())
686 if((*i)->get_sensor_id()!=addr)
699 if(result==1 && i!=rsv_blocks.begin())
701 // Compute speed and update related state
702 float travel_time_secs = (Time::now()-last_entry_time)/Time::sec;
708 RealSpeed &rs = real_speed[current_speed];
709 rs.add(travel_dist/travel_time_secs, travel_time_secs);
711 set_status(format("Traveling %d kmh", get_travel_speed()));
715 for(BlockList::iterator j=rsv_blocks.begin(); j!=i; ++j)
717 travel_dist += (*j)->get_path_length(j->entry());
719 if((*j)->get_sensor_id()==addr && !advancing)
721 TrackIter track = j->track_iter();
724 track = track.flip();
725 vehicles.back()->place(*track, track.entry(), 0, Vehicle::BACK_AXLE);
728 vehicles.front()->place(*track, track.entry(), 0, Vehicle::FRONT_AXLE);
731 last_entry_time = Time::now();
733 accurate_position = true;
736 // Check if we've reached the next route
739 const set<Track *> &rtracks = (++routes.begin())->route->get_tracks();
740 for(BlockList::iterator j=rsv_blocks.begin(); j!=i; ++j)
741 if(rtracks.count((*j)->get_endpoints()[j->entry()].track))
745 signal_route_changed.emit(routes.front().route);
750 // Move blocks up to the next sensor to our current blocks
751 cur_blocks.splice(cur_blocks.end(), rsv_blocks, rsv_blocks.begin(), i);
753 // Try to get more blocks if we're moving
758 layout.emergency("Sensor for "+name+" triggered out of order");
762 const Vehicle &veh = *(reverse ? vehicles.front() : vehicles.back());
764 // Find the first sensor in our current blocks that's still active
765 BlockList::iterator end = cur_blocks.begin();
766 for(BlockList::iterator i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
768 if((*i)->has_track(*veh.get_track()))
770 if((*i)->get_sensor_id())
772 if(layout.get_driver().get_sensor((*i)->get_sensor_id()))
782 if(end!=cur_blocks.begin() && end!=cur_blocks.end())
783 // Free blocks up to the last inactive sensor
784 release_blocks(cur_blocks, cur_blocks.begin(), end);
788 void Train::turnout_event(unsigned addr, bool)
790 if(pending_block && (!pending_block->get_train() || pending_block->get_train()==this))
792 unsigned pending_addr = pending_block->get_turnout_id();
793 bool double_addr = (*pending_block->get_tracks().begin())->get_type().is_double_address();
794 if(addr==pending_addr || (double_addr && addr==pending_addr+1))
804 void Train::halt_event(bool h)
807 accurate_position = false;
810 void Train::block_reserved(const Block &block, const Train *train)
812 if(&block==pending_block && !train && !reserving)
816 unsigned Train::reserve_more()
822 if(!rsv_blocks.empty())
823 start = rsv_blocks.back();
824 else if(!cur_blocks.empty())
825 start = cur_blocks.back();
831 // See how many sensor blocks and how much track we already have
834 for(BlockList::const_iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
836 if((*i)->get_sensor_id())
839 dist += (*i)->get_path_length(i->entry());
845 list<RouteRef>::iterator cur_route = routes.begin();
846 advance_route(cur_route, *start.track_iter());
848 float approach_margin = 50*layout.get_catalogue().get_scale();
849 float min_dist = controller->get_braking_distance()*1.3+approach_margin*2;
851 BlockIter block = start;
852 BlockIter good = start;
853 Track *divert_track = 0;
854 bool try_divert = false;
855 unsigned good_sens = nsens;
856 float good_dist = dist;
857 Train *blocking_train = 0;
858 BlockList contested_blocks;
860 SetFlag setf(reserving);
862 while(good_sens<3 || good_dist<min_dist || !contested_blocks.empty())
864 BlockIter last = block;
865 block = block.next(cur_route!=routes.end() ? cur_route->route : 0);
869 TrackIter track = block.track_iter();
871 if(cur_route!=routes.end())
873 if(!advance_route(cur_route, *track))
875 // Keep the blocks if we arrived at the end of the route
886 else if(!routes.empty() && routes.front().route->has_track(*track))
887 cur_route = routes.begin();
889 if(block->get_endpoints().size()<2)
902 if(block->get_train()!=blocking_train)
904 if(blocking_train->free_block(*contested_blocks.back()))
906 // Roll back and start actually reserving the blocks
907 block = rsv_blocks.back();
908 cur_route = routes.begin();
909 advance_route(cur_route, *block.track_iter().track());
910 if(blocking_train->get_priority()==priority)
911 blocking_train->yield_to(*this);
917 yield_to(*blocking_train);
918 pending_block = contested_blocks.front().block();
919 try_divert = divert_track;
925 contested_blocks.push_back(block);
930 bool reserved = block->reserve(this);
933 /* We've found another train. If it wants to exit the block from the
934 same endpoint we're trying to enter from or the other way around,
935 treat it as coming towards us. Otherwise treat it as going in the
937 Train *other_train = block->get_train();
938 int other_entry = other_train->get_entry_to_block(*block);
940 throw LogicError("Block reservation inconsistency");
942 unsigned exit = block.reverse().entry();
943 unsigned other_exit = BlockIter(block.block(), other_entry).reverse().entry();
944 bool entry_conflict = (block.entry()==other_exit);
945 bool exit_conflict = (exit==static_cast<unsigned>(other_entry));
946 if(!entry_conflict && !last->get_turnout_id())
948 /* The other train is not coming to the blocks we're holding, so we
955 int other_prio = other_train->get_priority();
957 if(!entry_conflict && !exit_conflict && other_prio<priority)
959 /* Ask a lesser priority train going to the same direction to free
961 if(other_train->free_block(*block))
962 reserved = block->reserve(this);
964 else if(other_train!=yielding_to && (other_prio<priority || (other_prio==priority && entry_conflict)))
966 /* A lesser priority train is coming at us, we must ask it to free
967 enough blocks to get clear of it to avoid a potential deadlock */
968 blocking_train = other_train;
969 contested_blocks.clear();
970 contested_blocks.push_back(block);
973 else if(divert_track && (entry_conflict || exit_conflict))
974 // We are blocked, but there's a diversion possibility
979 pending_block = &*block;
984 if(block->get_turnout_id())
986 const TrackType::Endpoint &track_ep = track->get_type().get_endpoints()[track.entry()];
987 bool multiple_paths = (track_ep.paths&(track_ep.paths-1));
989 if(multiple_paths || !last->get_turnout_id())
991 /* We can keep the blocks reserved so far if we are facing the
992 points or if there was no turnout immediately before this one.
993 With multiple successive turnouts (as is common in crossovers) it's
994 best to hold at one we can divert from. */
1000 // Figure out what path we'd like to take on the turnout
1002 for(list<RouteRef>::iterator i=cur_route; (path<0 && i!=routes.end()); ++i)
1003 path = i->route->get_turnout(block->get_turnout_id());
1005 path = track->get_active_path();
1006 if(!(track_ep.paths&(1<<path)))
1008 for(unsigned i=0; track_ep.paths>>i; ++i)
1009 if(track_ep.paths&(1<<i))
1013 if(path!=static_cast<int>(track->get_active_path()))
1015 // The turnout is set to wrong path - switch and wait for it
1016 pending_block = &*block;
1017 track->set_active_path(path);
1025 if(multiple_paths && cur_route!=routes.end() && cur_route->diversion!=block->get_turnout_id())
1026 /* There's multiple paths to be taken and we are on a route - take
1027 note of the diversion possibility */
1028 divert_track = &*track;
1031 if(!contested_blocks.empty() && contested_blocks.front()==block)
1032 contested_blocks.pop_front();
1034 rsv_blocks.push_back(block);
1035 if(block->get_sensor_id())
1038 dist += block->get_path_length(block.entry());
1041 // Unreserve blocks that were not good
1042 while(!rsv_blocks.empty() && rsv_blocks.back()!=good)
1044 rsv_blocks.back()->reserve(0);
1045 rsv_blocks.pop_back();
1048 if(!rsv_blocks.empty() && rsv_blocks.back()!=start)
1049 // We got some new blocks, so no longer need to yield
1052 // Make any sensorless blocks at the beginning immediately current
1053 BlockList::iterator i;
1054 for(i=rsv_blocks.begin(); (i!=rsv_blocks.end() && !(*i)->get_sensor_id()); ++i) ;
1055 if(i!=rsv_blocks.begin())
1056 cur_blocks.splice(cur_blocks.end(), rsv_blocks, rsv_blocks.begin(), i);
1058 if(try_divert && divert(*divert_track))
1059 return reserve_more();
1064 float Train::get_reserved_distance_until(const Block *until_block, bool back) const
1066 if(cur_blocks.empty())
1069 Vehicle &veh = *(reverse!=back ? vehicles.back() : vehicles.front());
1070 const VehicleType &vtype = veh.get_type();
1072 TrackIter track(veh.get_track(), veh.get_entry());
1076 BlockList::const_iterator block = cur_blocks.begin();
1077 while(block!=rsv_blocks.end() && !(*block)->has_track(*track))
1080 if(block==cur_blocks.end())
1084 block = rsv_blocks.begin();
1087 if(block==rsv_blocks.end() || &**block==until_block)
1090 float result = veh.get_offset();
1092 track = track.reverse();
1094 result = track->get_type().get_path_length(track->get_active_path())-result;
1095 result -= vtype.get_length()/2;
1099 track = track.next();
1103 if(!(*block)->has_track(*track))
1107 if(block==cur_blocks.begin())
1114 if(block==cur_blocks.end())
1115 block = rsv_blocks.begin();
1116 if(block==rsv_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
1132 if(real_speed[i].weight)
1133 return real_speed[i].speed;
1137 for(low=i; low>0; --low)
1138 if(real_speed[low].weight)
1140 for(high=i; high<14; ++high)
1141 if(real_speed[high].weight)
1144 if(real_speed[high].weight)
1146 if(real_speed[low].weight)
1148 float f = float(i-low)/(high-low);
1149 return real_speed[low].speed*(1-f)+real_speed[high].speed*f;
1152 return real_speed[high].speed*float(i)/high;
1154 else if(real_speed[low].weight)
1155 return real_speed[low].speed*float(i)/low;
1160 unsigned Train::find_speed(float real) const
1162 if(real<=real_speed[0].speed)
1168 for(unsigned i=0; (!high && i<=14); ++i)
1169 if(real_speed[i].weight)
1172 if(real_speed[i].speed<real)
1186 return min(min(static_cast<unsigned>(low*real/real_speed[low].speed), 14U), last+3);
1189 float f = (real-real_speed[low].speed)/(real_speed[high].speed-real_speed[low].speed);
1190 return static_cast<unsigned>(low*(1-f)+high*f+0.5);
1193 float Train::get_travel_speed() const
1195 float speed = get_real_speed(current_speed);
1196 float scale = layout.get_catalogue().get_scale();
1197 return static_cast<int>(round(speed/scale*3.6/5))*5;
1200 void Train::set_status(const string &s)
1203 signal_status_changed.emit(s);
1206 void Train::release_blocks(BlockList &blocks)
1208 release_blocks(blocks, blocks.begin(), blocks.end());
1211 void Train::release_blocks(BlockList &blocks, BlockList::iterator begin, BlockList::iterator end)
1215 Block &block = **begin;
1216 blocks.erase(begin++);
1221 void Train::reverse_blocks(BlockList &blocks) const
1224 for(BlockList::iterator i=blocks.begin(); i!=blocks.end(); ++i)
1228 bool Train::advance_route(list<RouteRef>::iterator &iter, Track &track)
1230 while(iter!=routes.end() && !iter->route->has_track(track))
1232 if(iter==routes.end())
1235 list<RouteRef>::iterator next = iter;
1237 if(next!=routes.end() && next->diversion && next->route->has_track(track))
1243 Route *Train::create_lead_route(Route *lead, const Route *target)
1247 lead = new Route(layout);
1248 lead->set_name("Lead");
1249 lead->set_temporary(true);
1252 set<Track *> tracks;
1253 for(BlockList::iterator i=cur_blocks.begin(); i!=rsv_blocks.end(); )
1255 const set<Track *> &btracks = (*i)->get_tracks();
1256 for(set<Track *>::const_iterator j=btracks.begin(); j!=btracks.end(); ++j)
1257 if(!target || !target->has_track(**j))
1260 if(++i==cur_blocks.end())
1261 i = rsv_blocks.begin();
1264 lead->add_tracks(tracks);
1269 bool Train::is_valid_diversion(const Route &diversion, const TrackIter &from)
1271 float diversion_len = 0;
1272 TrackLoopIter track1 = from;
1273 while(diversion.has_track(*track1))
1275 unsigned path = diversion.get_path(*track1);
1276 diversion_len += track1->get_type().get_path_length(path);
1278 track1 = track1.next(path);
1284 list<RouteRef>::iterator route = routes.begin();
1285 if(!advance_route(route, *from))
1288 float route_len = 0;
1289 TrackLoopIter track2 = from;
1292 unsigned path = route->route->get_path(*track2);
1293 route_len += track2->get_type().get_path_length(path);
1295 bool ok = (track2!=from && diversion.has_track(*track2));
1297 track2 = track2.next(path);
1305 if(!advance_route(route, *track2))
1309 // Must end up at the same place through both routes
1313 return diversion_len<route_len*1.2;
1317 Train::RouteRef::RouteRef(const Route *r, unsigned d):
1323 Train::RealSpeed::RealSpeed():
1328 void Train::RealSpeed::add(float s, float w)
1330 speed = (speed*weight+s*w)/(weight+w);
1331 weight = min(weight+w, 300.0f);
1335 Train::Loader::Loader(Train &t):
1336 DataFile::BasicLoader<Train>(t),
1340 add("block", &Loader::block);
1341 add("block_hint", &Loader::block_hint);
1342 add("name", &Loader::name);
1343 add("priority", &Train::priority);
1344 add("real_speed", &Loader::real_speed);
1345 add("route", &Loader::route);
1346 add("timetable", &Loader::timetable);
1347 add("vehicle", &Loader::vehicle);
1350 void Train::Loader::finish()
1352 if(!obj.cur_blocks.empty())
1354 TrackIter track = obj.cur_blocks.front().track_iter();
1355 float offset = 2*obj.layout.get_catalogue().get_scale();
1356 obj.vehicles.back()->place(*track, track.entry(), offset, Vehicle::BACK_BUFFER);
1358 obj.set_status("Stopped");
1362 void Train::Loader::block(unsigned id)
1370 blk = &obj.layout.get_block(id);
1372 catch(const KeyError &)
1374 blocks_valid = false;
1380 entry = blk->get_endpoint_by_link(*prev_block);
1385 obj.cur_blocks.push_back(BlockIter(blk, entry));
1387 if(blk->get_sensor_id())
1388 obj.layout.get_driver().set_sensor(blk->get_sensor_id(), true);
1393 void Train::Loader::block_hint(unsigned id)
1397 prev_block = &obj.layout.get_block(id);
1399 catch(const KeyError &)
1401 blocks_valid = false;
1405 void Train::Loader::name(const string &n)
1410 void Train::Loader::real_speed(unsigned i, float speed, float weight)
1412 obj.real_speed[i].speed = speed;
1413 obj.real_speed[i].weight = weight;
1416 void Train::Loader::route(const string &n)
1418 obj.set_route(&obj.layout.get_route(n));
1421 void Train::Loader::timetable()
1424 throw InvalidState("A timetable has already been loaded");
1426 obj.timetable = new Timetable(obj);
1427 load_sub(*obj.timetable);
1430 void Train::Loader::vehicle(ArticleNumber art_nr)
1432 const VehicleType &vtype = obj.layout.get_catalogue().get_vehicle(art_nr);
1433 Vehicle *veh = new Vehicle(obj.layout, vtype);
1434 obj.vehicles.back()->attach_back(*veh);
1435 obj.vehicles.push_back(veh);
1438 } // namespace Marklin