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 void Train::set_route(const Route *r)
209 free_noncritical_blocks();
214 end_of_route = false;
216 if(r && !cur_blocks.empty())
218 TrackIter first = cur_blocks.front().track_iter();
219 TrackIter next = (rsv_blocks.empty() ? cur_blocks : rsv_blocks).back().next().track_iter();
220 if(!r->has_track(*next))
222 Route *lead = Route::find(*next, next.entry(), *r);
223 create_lead_route(lead, lead);
224 routes.push_front(lead);
226 else if(!r->has_track(*first))
227 routes.push_front(create_lead_route(0, r));
232 signal_route_changed.emit(get_route());
235 void Train::go_to(Track &to)
237 for(BlockList::const_iterator i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
238 if((*i)->has_track(to))
240 signal_arrived.emit();
245 free_noncritical_blocks();
247 TrackIter next = (rsv_blocks.empty() ? cur_blocks : rsv_blocks).back().next().track_iter();
249 Route *route = Route::find(*next, next.entry(), to);
250 create_lead_route(route, route);
254 bool Train::divert(Track &from)
256 if(!from.get_turnout_id())
257 throw InvalidParameterValue("Can't divert from a non-turnout");
262 unsigned from_ep = 0;
263 list<RouteRef>::iterator route = routes.begin();
264 BlockIter block = cur_blocks.back();
265 set<const Track *> visited;
267 // Follow our routes to find out where we're entering the turnout
270 block = block.next(route->route);
272 const Block::Endpoint &entry_ep = block->get_endpoints()[block.entry()];
274 if(visited.count(entry_ep.track))
276 visited.insert(entry_ep.track);
278 if(!advance_route(route, *entry_ep.track))
281 if(entry_ep.track==&from)
283 if(block->get_train()==this && !free_block(*block))
286 from_ep = entry_ep.track_ep;
287 path = route->route->get_turnout(from.get_turnout_id());
292 // Check that more than one path is available
293 unsigned ep_paths = from.get_type().get_endpoints()[from_ep].paths;
294 if(!(ep_paths&(ep_paths-1)))
297 // Choose some other path
298 for(int i=0; ep_paths>>i; ++i)
299 if((ep_paths&(1<<i)) && i!=path)
305 TrackIter track = TrackIter(&from, from_ep).next(path);
309 unsigned ep = track->get_endpoint_by_link(from);
312 for(list<RouteRef>::iterator i=routes.begin(); i!=routes.end(); ++i)
313 tracks.insert(i->route->get_tracks().begin(), i->route->get_tracks().end());
314 Route *diversion = 0;
317 diversion = Route::find(*track, ep, tracks);
319 catch(const Msp::Exception &)
324 diversion->set_name("Diversion");
325 diversion->add_track(from);
326 diversion->set_turnout(from.get_turnout_id(), path);
328 if(!is_valid_diversion(*diversion, from, from_ep))
334 // Follow the diversion route until we get back to the original route
335 list<RouteRef>::iterator end = routes.end();
338 for(list<RouteRef>::iterator i=route; (end==routes.end() && i!=routes.end()); ++i)
339 if(i->route->has_track(*track))
342 if(end!=routes.end())
344 else if(!diversion->has_track(*track))
345 throw Exception("Pathfinder returned a bad route");
347 unsigned tid = track->get_turnout_id();
348 track = track.next(tid ? diversion->get_turnout(tid) : 0);
352 // We are rejoining the same route we diverted from, duplicate it
353 routes.insert(end, *route);
357 routes.erase(route, end);
359 routes.insert(end, RouteRef(diversion, from.get_turnout_id()));
364 const Route *Train::get_route() const
368 return routes.front().route;
371 void Train::place(Block &block, unsigned entry)
373 if(controller->get_speed())
374 throw InvalidState("Must be stopped before placing");
376 release_blocks(rsv_blocks);
377 release_blocks(cur_blocks);
380 accurate_position = false;
382 if(!block.reserve(this))
384 set_status("Unplaced");
388 cur_blocks.push_back(BlockIter(&block, entry));
391 TrackIter track = BlockIter(&block, entry).reverse().track_iter();
392 vehicles.front()->place(*track, track.entry(), 0, Vehicle::FRONT_BUFFER);
396 const Block::Endpoint &bep = block.get_endpoints()[entry];
397 vehicles.back()->place(*bep.track, bep.track_ep, 0, Vehicle::BACK_BUFFER);
401 void Train::unplace()
403 if(controller->get_speed())
404 throw InvalidState("Must be stopped before unplacing");
406 release_blocks(rsv_blocks);
407 release_blocks(cur_blocks);
410 accurate_position = false;
412 for(vector<Vehicle *>::iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
415 set_status("Unplaced");
418 bool Train::free_block(Block &block)
420 float margin = 10*layout.get_catalogue().get_scale();
421 if(get_reserved_distance_until(&block, false)<controller->get_braking_distance()*1.3+margin)
425 for(BlockList::iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
427 if(i->block()==&block)
431 release_blocks(rsv_blocks, i, rsv_blocks.end());
434 else if((*i)->get_sensor_id())
441 void Train::free_noncritical_blocks()
443 if(cur_blocks.empty() || rsv_blocks.empty())
446 if(controller->get_speed()==0)
448 release_blocks(rsv_blocks);
452 float margin = 10*layout.get_catalogue().get_scale();
453 float min_dist = controller->get_braking_distance()*1.3+margin;
455 Vehicle &veh = *(reverse ? vehicles.back() : vehicles.front());
457 TrackIter track(veh.get_track(), veh.get_entry());
458 BlockList::iterator block = cur_blocks.begin();
460 while(block!=rsv_blocks.end() && !(*block)->has_track(*track))
463 if(block==cur_blocks.end())
465 block = rsv_blocks.begin();
470 float dist = veh.get_offset();
474 dist = track->get_type().get_path_length(track->get_active_path())-dist;
475 dist -= veh.get_type().get_length()/2;
480 track = track.next();
482 if(!(*block)->has_track(*track))
485 if(block==cur_blocks.end())
487 block = rsv_blocks.begin();
490 if(block==rsv_blocks.end())
493 if(dist>min_dist && nsens>0)
495 release_blocks(rsv_blocks, block, rsv_blocks.end());
499 if(in_rsv && (*block)->get_sensor_id())
503 dist += track->get_type().get_path_length(track->get_active_path());
507 int Train::get_entry_to_block(Block &block) const
509 for(BlockList::const_iterator i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
510 if(i->block()==&block)
512 for(BlockList::const_iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
513 if(i->block()==&block)
518 float Train::get_reserved_distance() const
520 return get_reserved_distance_until(0, false);
523 void Train::tick(const Time::TimeStamp &t, const Time::TimeDelta &dt)
525 if(!active && stop_timeout && t>=stop_timeout)
527 release_blocks(rsv_blocks);
528 end_of_route = false;
529 stop_timeout = Time::TimeStamp();
532 Driver &driver = layout.get_driver();
536 controller->tick(dt);
537 float speed = controller->get_speed();
538 unsigned speed_notch = find_speed(speed);
540 if(controller->get_reverse()!=reverse)
542 reverse = controller->get_reverse();
543 driver.set_loco_reverse(address, reverse);
545 release_blocks(rsv_blocks);
546 reverse_blocks(cur_blocks);
550 if(speed_notch!=current_speed && !speed_changing && !driver.is_halted() && driver.get_power())
552 speed_changing = true;
553 driver.set_loco_speed(address, speed_notch);
558 set_status(format("Traveling %d kmh", get_travel_speed()));
560 set_status("Waiting");
568 Vehicle &vehicle = *(reverse ? vehicles.back() : vehicles.front());
569 Track *track = vehicle.get_track();
572 for(BlockList::const_iterator i=cur_blocks.begin(); (!ok && i!=cur_blocks.end()); ++i)
573 ok = (*i)->has_track(*track);
575 float d = get_real_speed(current_speed)*(dt/Time::sec);
578 SetFlag setf(advancing);
579 vehicle.advance(reverse ? -d : d);
581 else if(accurate_position)
584 if(overshoot_dist>40*layout.get_catalogue().get_scale())
586 layout.emergency(name+" has not arrived at sensor");
587 accurate_position = false;
591 else if(end_of_route && rsv_blocks.empty())
594 signal_arrived.emit();
598 if(!cur_blocks.empty() && !cur_blocks.front()->get_sensor_id())
600 float dist = get_reserved_distance_until(&*cur_blocks.front(), true);
602 if(dist>10*layout.get_catalogue().get_scale())
604 cur_blocks.front()->reserve(0);
605 cur_blocks.pop_front();
610 void Train::save(list<DataFile::Statement> &st) const
612 st.push_back((DataFile::Statement("name"), name));
614 st.push_back((DataFile::Statement("priority"), priority));
616 for(vector<Vehicle *>::const_iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
617 if(i!=vehicles.begin())
618 st.push_back((DataFile::Statement("vehicle"), (*i)->get_type().get_article_number()));
620 for(unsigned i=0; i<=14; ++i)
621 if(real_speed[i].weight)
622 st.push_back((DataFile::Statement("real_speed"), i, real_speed[i].speed, real_speed[i].weight));
624 if(!cur_blocks.empty())
626 BlockList blocks = cur_blocks;
628 reverse_blocks(blocks);
630 BlockIter prev = blocks.front().flip();
631 st.push_back((DataFile::Statement("block_hint"), prev->get_id()));
633 for(BlockList::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
634 st.push_back((DataFile::Statement("block"), (*i)->get_id()));
639 list<RouteRef>::const_iterator i = routes.begin();
640 for(; (i!=routes.end() && i->route->is_temporary()); ++i) ;
642 st.push_back((DataFile::Statement("route"), i->route->get_name()));
647 DataFile::Statement ss("timetable");
648 timetable->save(ss.sub);
653 void Train::control_changed(const Controller::Control &ctrl)
655 signal_control_changed.emit(ctrl.name, ctrl.value);
658 void Train::loco_speed_event(unsigned addr, unsigned speed, bool)
662 current_speed = speed;
663 speed_changing = false;
668 void Train::loco_func_event(unsigned addr, unsigned func, bool state)
670 if(addr==address || (addr==address+1 && loco_type.get_max_function()>4))
675 functions |= 1<<func;
677 functions &= ~(1<<func);
679 signal_function_changed.emit(func, state);
683 void Train::sensor_event(unsigned addr, bool state)
687 // Find the first sensor block from our reserved blocks that isn't this sensor
688 BlockList::iterator i;
690 for(i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
691 if((*i)->get_sensor_id())
693 if((*i)->get_sensor_id()!=addr)
706 if(result==1 && i!=rsv_blocks.begin())
708 // Compute speed and update related state
709 float travel_time_secs = (Time::now()-last_entry_time)/Time::sec;
715 RealSpeed &rs = real_speed[current_speed];
716 rs.add(travel_dist/travel_time_secs, travel_time_secs);
718 set_status(format("Traveling %d kmh", get_travel_speed()));
722 for(BlockList::iterator j=rsv_blocks.begin(); j!=i; ++j)
724 travel_dist += (*j)->get_path_length(j->entry());
726 if((*j)->get_sensor_id()==addr && !advancing)
728 TrackIter track = j->track_iter();
731 track = track.flip();
732 vehicles.back()->place(*track, track.entry(), 0, Vehicle::BACK_AXLE);
735 vehicles.front()->place(*track, track.entry(), 0, Vehicle::FRONT_AXLE);
738 last_entry_time = Time::now();
740 accurate_position = true;
743 // Check if we've reached the next route
746 const set<Track *> &rtracks = (++routes.begin())->route->get_tracks();
747 for(BlockList::iterator j=rsv_blocks.begin(); j!=i; ++j)
748 if(rtracks.count((*j)->get_endpoints()[j->entry()].track))
752 signal_route_changed.emit(routes.front().route);
757 // Move blocks up to the next sensor to our current blocks
758 cur_blocks.splice(cur_blocks.end(), rsv_blocks, rsv_blocks.begin(), i);
760 // Try to get more blocks if we're moving
765 layout.emergency("Sensor for "+name+" triggered out of order");
769 const Vehicle &veh = *(reverse ? vehicles.front() : vehicles.back());
771 // Find the first sensor in our current blocks that's still active
772 BlockList::iterator end = cur_blocks.begin();
773 for(BlockList::iterator i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
775 if((*i)->has_track(*veh.get_track()))
777 if((*i)->get_sensor_id())
779 if(layout.get_driver().get_sensor((*i)->get_sensor_id()))
789 if(end!=cur_blocks.begin() && end!=cur_blocks.end())
790 // Free blocks up to the last inactive sensor
791 release_blocks(cur_blocks, cur_blocks.begin(), end);
795 void Train::turnout_event(unsigned addr, bool)
797 if(pending_block && (!pending_block->get_train() || pending_block->get_train()==this))
799 unsigned pending_addr = pending_block->get_turnout_id();
800 bool double_addr = (*pending_block->get_tracks().begin())->get_type().is_double_address();
801 if(addr==pending_addr || (double_addr && addr==pending_addr+1))
811 void Train::halt_event(bool h)
814 accurate_position = false;
817 void Train::block_reserved(const Block &block, const Train *train)
819 if(&block==pending_block && !train && !reserving)
823 unsigned Train::reserve_more()
829 if(!rsv_blocks.empty())
830 start = rsv_blocks.back();
831 else if(!cur_blocks.empty())
832 start = cur_blocks.back();
838 // See how many sensor blocks and how much track we already have
841 for(BlockList::const_iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
843 if((*i)->get_sensor_id())
846 dist += (*i)->get_path_length(i->entry());
852 list<RouteRef>::iterator cur_route = routes.begin();
853 advance_route(cur_route, *start.track_iter());
855 float approach_margin = 50*layout.get_catalogue().get_scale();
856 float min_dist = controller->get_braking_distance()*1.3+approach_margin*2;
858 BlockIter block = start;
859 BlockIter good = start;
860 Track *divert_track = 0;
861 bool try_divert = false;
862 unsigned good_sens = nsens;
863 float good_dist = dist;
864 Train *blocking_train = 0;
865 BlockList contested_blocks;
867 SetFlag setf(reserving);
869 while(good_sens<3 || good_dist<min_dist || !contested_blocks.empty())
871 BlockIter last = block;
872 block = block.next(cur_route!=routes.end() ? cur_route->route : 0);
876 TrackIter track = block.track_iter();
878 if(cur_route!=routes.end())
880 if(!advance_route(cur_route, *track))
882 // Keep the blocks if we arrived at the end of the route
893 else if(!routes.empty() && routes.front().route->has_track(*track))
894 cur_route = routes.begin();
896 if(block->get_endpoints().size()<2)
909 if(block->get_train()!=blocking_train)
911 if(blocking_train->free_block(*contested_blocks.back()))
913 // Roll back and start actually reserving the blocks
914 block = rsv_blocks.back();
915 cur_route = routes.begin();
916 advance_route(cur_route, *block.track_iter().track());
917 if(blocking_train->get_priority()==priority)
918 blocking_train->yield_to(*this);
924 yield_to(*blocking_train);
925 pending_block = contested_blocks.front().block();
926 try_divert = divert_track;
932 contested_blocks.push_back(block);
937 bool reserved = block->reserve(this);
940 /* We've found another train. If it wants to exit the block from the
941 same endpoint we're trying to enter from or the other way around,
942 treat it as coming towards us. Otherwise treat it as going in the
944 Train *other_train = block->get_train();
945 int other_entry = other_train->get_entry_to_block(*block);
947 throw LogicError("Block reservation inconsistency");
949 unsigned exit = block.reverse().entry();
950 unsigned other_exit = BlockIter(block.block(), other_entry).reverse().entry();
951 bool entry_conflict = (block.entry()==other_exit);
952 bool exit_conflict = (exit==static_cast<unsigned>(other_entry));
953 if(!entry_conflict && !last->get_turnout_id())
955 /* The other train is not coming to the blocks we're holding, so we
962 int other_prio = other_train->get_priority();
964 if(!entry_conflict && !exit_conflict && other_prio<priority)
966 /* Ask a lesser priority train going to the same direction to free
968 if(other_train->free_block(*block))
969 reserved = block->reserve(this);
971 else if(other_train!=yielding_to && (other_prio<priority || (other_prio==priority && entry_conflict)))
973 /* A lesser priority train is coming at us, we must ask it to free
974 enough blocks to get clear of it to avoid a potential deadlock */
975 blocking_train = other_train;
976 contested_blocks.clear();
977 contested_blocks.push_back(block);
980 else if(divert_track && (entry_conflict || exit_conflict))
981 // We are blocked, but there's a diversion possibility
986 pending_block = &*block;
991 if(block->get_turnout_id())
993 const TrackType::Endpoint &track_ep = track->get_type().get_endpoints()[track.entry()];
994 bool multiple_paths = (track_ep.paths&(track_ep.paths-1));
996 if(multiple_paths || !last->get_turnout_id())
998 /* We can keep the blocks reserved so far if we are facing the
999 points or if there was no turnout immediately before this one.
1000 With multiple successive turnouts (as is common in crossovers) it's
1001 best to hold at one we can divert from. */
1007 // Figure out what path we'd like to take on the turnout
1009 for(list<RouteRef>::iterator i=cur_route; (path<0 && i!=routes.end()); ++i)
1010 path = i->route->get_turnout(block->get_turnout_id());
1012 path = track->get_active_path();
1013 if(!(track_ep.paths&(1<<path)))
1015 for(unsigned i=0; track_ep.paths>>i; ++i)
1016 if(track_ep.paths&(1<<i))
1020 if(path!=static_cast<int>(track->get_active_path()))
1022 // The turnout is set to wrong path - switch and wait for it
1023 pending_block = &*block;
1024 track->set_active_path(path);
1032 if(multiple_paths && cur_route!=routes.end() && cur_route->diversion!=block->get_turnout_id())
1033 /* There's multiple paths to be taken and we are on a route - take
1034 note of the diversion possibility */
1035 divert_track = &*track;
1038 if(!contested_blocks.empty() && contested_blocks.front()==block)
1039 contested_blocks.pop_front();
1041 rsv_blocks.push_back(block);
1042 if(block->get_sensor_id())
1045 dist += block->get_path_length(block.entry());
1048 // Unreserve blocks that were not good
1049 while(!rsv_blocks.empty() && rsv_blocks.back()!=good)
1051 rsv_blocks.back()->reserve(0);
1052 rsv_blocks.pop_back();
1055 if(!rsv_blocks.empty() && rsv_blocks.back()!=start)
1056 // We got some new blocks, so no longer need to yield
1059 // Make any sensorless blocks at the beginning immediately current
1060 BlockList::iterator i;
1061 for(i=rsv_blocks.begin(); (i!=rsv_blocks.end() && !(*i)->get_sensor_id()); ++i) ;
1062 if(i!=rsv_blocks.begin())
1063 cur_blocks.splice(cur_blocks.end(), rsv_blocks, rsv_blocks.begin(), i);
1065 if(try_divert && divert(*divert_track))
1066 return reserve_more();
1071 float Train::get_reserved_distance_until(const Block *until_block, bool back) const
1073 if(cur_blocks.empty())
1076 Vehicle &veh = *(reverse!=back ? vehicles.back() : vehicles.front());
1077 const VehicleType &vtype = veh.get_type();
1079 TrackIter track(veh.get_track(), veh.get_entry());
1083 BlockList::const_iterator block = cur_blocks.begin();
1084 while(block!=rsv_blocks.end() && !(*block)->has_track(*track))
1087 if(block==cur_blocks.end())
1091 block = rsv_blocks.begin();
1094 if(block==rsv_blocks.end() || &**block==until_block)
1097 float result = veh.get_offset();
1099 track = track.reverse();
1101 result = track->get_type().get_path_length(track->get_active_path())-result;
1102 result -= vtype.get_length()/2;
1106 track = track.next();
1110 if(!(*block)->has_track(*track))
1114 if(block==cur_blocks.begin())
1121 if(block==cur_blocks.end())
1122 block = rsv_blocks.begin();
1123 if(block==rsv_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
1139 if(real_speed[i].weight)
1140 return real_speed[i].speed;
1144 for(low=i; low>0; --low)
1145 if(real_speed[low].weight)
1147 for(high=i; high<14; ++high)
1148 if(real_speed[high].weight)
1151 if(real_speed[high].weight)
1153 if(real_speed[low].weight)
1155 float f = float(i-low)/(high-low);
1156 return real_speed[low].speed*(1-f)+real_speed[high].speed*f;
1159 return real_speed[high].speed*float(i)/high;
1161 else if(real_speed[low].weight)
1162 return real_speed[low].speed*float(i)/low;
1167 unsigned Train::find_speed(float real) const
1169 if(real<=real_speed[0].speed)
1175 for(unsigned i=0; (!high && i<=14); ++i)
1176 if(real_speed[i].weight)
1179 if(real_speed[i].speed<real)
1193 return min(min(static_cast<unsigned>(low*real/real_speed[low].speed), 14U), last+3);
1196 float f = (real-real_speed[low].speed)/(real_speed[high].speed-real_speed[low].speed);
1197 return static_cast<unsigned>(low*(1-f)+high*f+0.5);
1200 float Train::get_travel_speed() const
1202 float speed = get_real_speed(current_speed);
1203 float scale = layout.get_catalogue().get_scale();
1204 return static_cast<int>(round(speed/scale*3.6/5))*5;
1207 void Train::set_status(const string &s)
1210 signal_status_changed.emit(s);
1213 void Train::release_blocks(BlockList &blocks)
1215 release_blocks(blocks, blocks.begin(), blocks.end());
1218 void Train::release_blocks(BlockList &blocks, BlockList::iterator begin, BlockList::iterator end)
1222 Block &block = **begin;
1223 blocks.erase(begin++);
1228 void Train::reverse_blocks(BlockList &blocks) const
1231 for(BlockList::iterator i=blocks.begin(); i!=blocks.end(); ++i)
1235 bool Train::advance_route(list<RouteRef>::iterator &iter, Track &track)
1237 while(iter!=routes.end() && !iter->route->has_track(track))
1239 if(iter==routes.end())
1242 list<RouteRef>::iterator next = iter;
1244 if(next!=routes.end() && next->diversion && next->route->has_track(track))
1250 Route *Train::create_lead_route(Route *lead, const Route *target)
1254 lead = new Route(layout);
1255 lead->set_name("Lead");
1256 lead->set_temporary(true);
1259 set<Track *> tracks;
1260 for(BlockList::iterator i=cur_blocks.begin(); i!=rsv_blocks.end(); )
1262 const set<Track *> &btracks = (*i)->get_tracks();
1263 for(set<Track *>::const_iterator j=btracks.begin(); j!=btracks.end(); ++j)
1264 if(!target || !target->has_track(**j))
1267 if(++i==cur_blocks.end())
1268 i = rsv_blocks.begin();
1271 lead->add_tracks(tracks);
1276 bool Train::is_valid_diversion(const Route &diversion, Track &from, unsigned from_ep)
1278 float diversion_len = 0;
1279 TrackIter track(&from, from_ep);
1280 while(diversion.has_track(*track))
1282 unsigned tid = track->get_turnout_id();
1283 unsigned path = (tid ? diversion.get_turnout(tid) : 0);
1284 diversion_len += track->get_type().get_path_length(path);
1286 track = track.next(path);
1292 list<RouteRef>::iterator route = routes.begin();
1293 if(!advance_route(route, from))
1296 set<Track *> visited;
1297 float route_len = 0;
1298 track = TrackIter(&from, from_ep);
1301 unsigned tid = track->get_turnout_id();
1302 unsigned path = (tid ? route->route->get_turnout(tid) : 0);
1303 route_len += track->get_type().get_path_length(path);
1305 if(&*track!=&from && diversion.has_track(*track))
1308 if(visited.count(&*track))
1310 visited.insert(&*track);
1312 track = track.next(path);
1314 if(!advance_route(route, *track))
1318 return diversion_len<route_len*1.2;
1322 Train::RouteRef::RouteRef(const Route *r, unsigned d):
1328 Train::RealSpeed::RealSpeed():
1333 void Train::RealSpeed::add(float s, float w)
1335 speed = (speed*weight+s*w)/(weight+w);
1336 weight = min(weight+w, 300.0f);
1340 Train::Loader::Loader(Train &t):
1341 DataFile::BasicLoader<Train>(t),
1345 add("block", &Loader::block);
1346 add("block_hint", &Loader::block_hint);
1347 add("name", &Loader::name);
1348 add("priority", &Train::priority);
1349 add("real_speed", &Loader::real_speed);
1350 add("route", &Loader::route);
1351 add("timetable", &Loader::timetable);
1352 add("vehicle", &Loader::vehicle);
1355 void Train::Loader::finish()
1357 if(!obj.cur_blocks.empty())
1359 TrackIter track = obj.cur_blocks.front().track_iter();
1360 float offset = 2*obj.layout.get_catalogue().get_scale();
1361 obj.vehicles.back()->place(*track, track.entry(), offset, Vehicle::BACK_BUFFER);
1363 obj.set_status("Stopped");
1367 void Train::Loader::block(unsigned id)
1375 blk = &obj.layout.get_block(id);
1377 catch(const KeyError &)
1379 blocks_valid = false;
1385 entry = blk->get_endpoint_by_link(*prev_block);
1390 obj.cur_blocks.push_back(BlockIter(blk, entry));
1392 if(blk->get_sensor_id())
1393 obj.layout.get_driver().set_sensor(blk->get_sensor_id(), true);
1398 void Train::Loader::block_hint(unsigned id)
1402 prev_block = &obj.layout.get_block(id);
1404 catch(const KeyError &)
1406 blocks_valid = false;
1410 void Train::Loader::name(const string &n)
1415 void Train::Loader::real_speed(unsigned i, float speed, float weight)
1417 obj.real_speed[i].speed = speed;
1418 obj.real_speed[i].weight = weight;
1421 void Train::Loader::route(const string &n)
1423 obj.set_route(&obj.layout.get_route(n));
1426 void Train::Loader::timetable()
1429 throw InvalidState("A timetable has already been loaded");
1431 obj.timetable = new Timetable(obj);
1432 load_sub(*obj.timetable);
1435 void Train::Loader::vehicle(unsigned n)
1437 const VehicleType &vtype = obj.layout.get_catalogue().get_vehicle(n);
1438 Vehicle *veh = new Vehicle(obj.layout, vtype);
1439 obj.vehicles.back()->attach_back(*veh);
1440 obj.vehicles.push_back(veh);
1443 } // namespace Marklin