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, next.entry(), *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, next.entry(), 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");
270 unsigned from_ep = 0;
271 list<RouteRef>::iterator route = routes.begin();
272 BlockIter block = cur_blocks.back();
273 set<const Track *> visited;
275 // Follow our routes to find out where we're entering the turnout
278 block = block.next(route->route);
280 const Block::Endpoint &entry_ep = block->get_endpoints()[block.entry()];
282 if(visited.count(entry_ep.track))
284 visited.insert(entry_ep.track);
286 if(!advance_route(route, *entry_ep.track))
289 if(entry_ep.track==&from)
291 if(block->get_train()==this && !free_block(*block))
294 from_ep = entry_ep.track_ep;
295 path = route->route->get_turnout(from.get_turnout_id());
300 // Check that more than one path is available
301 unsigned ep_paths = from.get_type().get_endpoints()[from_ep].paths;
302 if(!(ep_paths&(ep_paths-1)))
305 // Choose some other path
306 for(int i=0; ep_paths>>i; ++i)
307 if((ep_paths&(1<<i)) && i!=path)
313 TrackIter track = TrackIter(&from, from_ep).next(path);
317 unsigned ep = track->get_endpoint_by_link(from);
320 for(list<RouteRef>::iterator i=routes.begin(); i!=routes.end(); ++i)
321 tracks.insert(i->route->get_tracks().begin(), i->route->get_tracks().end());
322 RefPtr<Route> diversion = Route::find(*track, ep, tracks);
326 diversion->set_name("Diversion");
327 diversion->add_track(from);
328 diversion->set_turnout(from.get_turnout_id(), path);
330 if(!is_valid_diversion(*diversion, from, from_ep))
333 // Follow the diversion route until we get back to the original route
334 list<RouteRef>::iterator end = routes.end();
337 for(list<RouteRef>::iterator i=route; (end==routes.end() && i!=routes.end()); ++i)
338 if(i->route->has_track(*track))
341 if(end!=routes.end())
343 else if(!diversion->has_track(*track))
344 throw LogicError("Pathfinder returned a bad route");
346 unsigned tid = track->get_turnout_id();
347 track = track.next(tid ? diversion->get_turnout(tid) : 0);
351 // We are rejoining the same route we diverted from, duplicate it
352 routes.insert(end, *route);
356 routes.erase(route, end);
358 routes.insert(end, RouteRef(diversion.release(), from.get_turnout_id()));
363 const Route *Train::get_route() const
367 return routes.front().route;
370 void Train::place(Block &block, unsigned entry)
372 if(controller->get_speed())
373 throw InvalidState("Must be stopped before placing");
375 release_blocks(rsv_blocks);
376 release_blocks(cur_blocks);
379 accurate_position = false;
381 if(!block.reserve(this))
383 set_status("Unplaced");
387 cur_blocks.push_back(BlockIter(&block, entry));
390 TrackIter track = BlockIter(&block, entry).reverse().track_iter();
391 vehicles.front()->place(*track, track.entry(), 0, Vehicle::FRONT_BUFFER);
395 const Block::Endpoint &bep = block.get_endpoints()[entry];
396 vehicles.back()->place(*bep.track, bep.track_ep, 0, Vehicle::BACK_BUFFER);
400 void Train::unplace()
402 if(controller->get_speed())
403 throw InvalidState("Must be stopped before unplacing");
405 release_blocks(rsv_blocks);
406 release_blocks(cur_blocks);
409 accurate_position = false;
411 for(vector<Vehicle *>::iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
414 set_status("Unplaced");
417 bool Train::free_block(Block &block)
419 float margin = 10*layout.get_catalogue().get_scale();
420 if(get_reserved_distance_until(&block, false)<controller->get_braking_distance()*1.3+margin)
424 for(BlockList::iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
426 if(i->block()==&block)
430 release_blocks(rsv_blocks, i, rsv_blocks.end());
433 else if((*i)->get_sensor_id())
440 void Train::free_noncritical_blocks()
442 if(cur_blocks.empty() || rsv_blocks.empty())
445 if(controller->get_speed()==0)
447 release_blocks(rsv_blocks);
451 float margin = 10*layout.get_catalogue().get_scale();
452 float min_dist = controller->get_braking_distance()*1.3+margin;
454 Vehicle &veh = *(reverse ? vehicles.back() : vehicles.front());
456 TrackIter track(veh.get_track(), veh.get_entry());
457 BlockList::iterator block = cur_blocks.begin();
459 while(block!=rsv_blocks.end() && !(*block)->has_track(*track))
462 if(block==cur_blocks.end())
464 block = rsv_blocks.begin();
469 float dist = veh.get_offset();
473 dist = track->get_type().get_path_length(track->get_active_path())-dist;
474 dist -= veh.get_type().get_length()/2;
479 track = track.next();
481 if(!(*block)->has_track(*track))
484 if(block==cur_blocks.end())
486 block = rsv_blocks.begin();
489 if(block==rsv_blocks.end())
492 if(dist>min_dist && nsens>0)
494 release_blocks(rsv_blocks, block, rsv_blocks.end());
498 if(in_rsv && (*block)->get_sensor_id())
502 dist += track->get_type().get_path_length(track->get_active_path());
506 int Train::get_entry_to_block(Block &block) const
508 for(BlockList::const_iterator i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
509 if(i->block()==&block)
511 for(BlockList::const_iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
512 if(i->block()==&block)
517 float Train::get_reserved_distance() const
519 return get_reserved_distance_until(0, false);
522 void Train::tick(const Time::TimeStamp &t, const Time::TimeDelta &dt)
524 if(!active && stop_timeout && t>=stop_timeout)
526 release_blocks(rsv_blocks);
527 end_of_route = false;
528 stop_timeout = Time::TimeStamp();
531 Driver &driver = layout.get_driver();
535 controller->tick(dt);
536 float speed = controller->get_speed();
537 unsigned speed_notch = find_speed(speed);
539 if(controller->get_reverse()!=reverse)
541 reverse = controller->get_reverse();
542 driver.set_loco_reverse(address, reverse);
544 release_blocks(rsv_blocks);
545 reverse_blocks(cur_blocks);
549 if(speed_notch!=current_speed && !speed_changing && !driver.is_halted() && driver.get_power())
551 speed_changing = true;
552 driver.set_loco_speed(address, speed_notch);
557 set_status(format("Traveling %d kmh", get_travel_speed()));
559 set_status("Waiting");
567 Vehicle &vehicle = *(reverse ? vehicles.back() : vehicles.front());
568 Track *track = vehicle.get_track();
571 for(BlockList::const_iterator i=cur_blocks.begin(); (!ok && i!=cur_blocks.end()); ++i)
572 ok = (*i)->has_track(*track);
574 float d = get_real_speed(current_speed)*(dt/Time::sec);
577 SetFlag setf(advancing);
578 vehicle.advance(reverse ? -d : d);
580 else if(accurate_position)
583 if(overshoot_dist>40*layout.get_catalogue().get_scale())
585 layout.emergency(name+" has not arrived at sensor");
586 accurate_position = false;
590 else if(end_of_route && rsv_blocks.empty())
593 signal_arrived.emit();
597 if(!cur_blocks.empty() && !cur_blocks.front()->get_sensor_id())
599 float dist = get_reserved_distance_until(&*cur_blocks.front(), true);
601 if(dist>10*layout.get_catalogue().get_scale())
603 cur_blocks.front()->reserve(0);
604 cur_blocks.pop_front();
609 void Train::save(list<DataFile::Statement> &st) const
611 st.push_back((DataFile::Statement("name"), name));
613 st.push_back((DataFile::Statement("priority"), priority));
615 for(vector<Vehicle *>::const_iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
616 if(i!=vehicles.begin())
617 st.push_back((DataFile::Statement("vehicle"), (*i)->get_type().get_article_number()));
619 for(unsigned i=0; i<=14; ++i)
620 if(real_speed[i].weight)
621 st.push_back((DataFile::Statement("real_speed"), i, real_speed[i].speed, real_speed[i].weight));
623 if(!cur_blocks.empty())
625 BlockList blocks = cur_blocks;
627 reverse_blocks(blocks);
629 BlockIter prev = blocks.front().flip();
630 st.push_back((DataFile::Statement("block_hint"), prev->get_id()));
632 for(BlockList::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
633 st.push_back((DataFile::Statement("block"), (*i)->get_id()));
638 list<RouteRef>::const_iterator i = routes.begin();
639 for(; (i!=routes.end() && i->route->is_temporary()); ++i) ;
641 st.push_back((DataFile::Statement("route"), i->route->get_name()));
646 DataFile::Statement ss("timetable");
647 timetable->save(ss.sub);
652 void Train::control_changed(const Controller::Control &ctrl)
654 signal_control_changed.emit(ctrl.name, ctrl.value);
657 void Train::loco_speed_event(unsigned addr, unsigned speed, bool)
661 current_speed = speed;
662 speed_changing = false;
667 void Train::loco_func_event(unsigned addr, unsigned func, bool state)
669 if(addr==address || (addr==address+1 && loco_type.get_max_function()>4))
674 functions |= 1<<func;
676 functions &= ~(1<<func);
678 signal_function_changed.emit(func, state);
682 void Train::sensor_event(unsigned addr, bool state)
686 // Find the first sensor block from our reserved blocks that isn't this sensor
687 BlockList::iterator i;
689 for(i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
690 if((*i)->get_sensor_id())
692 if((*i)->get_sensor_id()!=addr)
705 if(result==1 && i!=rsv_blocks.begin())
707 // Compute speed and update related state
708 float travel_time_secs = (Time::now()-last_entry_time)/Time::sec;
714 RealSpeed &rs = real_speed[current_speed];
715 rs.add(travel_dist/travel_time_secs, travel_time_secs);
717 set_status(format("Traveling %d kmh", get_travel_speed()));
721 for(BlockList::iterator j=rsv_blocks.begin(); j!=i; ++j)
723 travel_dist += (*j)->get_path_length(j->entry());
725 if((*j)->get_sensor_id()==addr && !advancing)
727 TrackIter track = j->track_iter();
730 track = track.flip();
731 vehicles.back()->place(*track, track.entry(), 0, Vehicle::BACK_AXLE);
734 vehicles.front()->place(*track, track.entry(), 0, Vehicle::FRONT_AXLE);
737 last_entry_time = Time::now();
739 accurate_position = true;
742 // Check if we've reached the next route
745 const set<Track *> &rtracks = (++routes.begin())->route->get_tracks();
746 for(BlockList::iterator j=rsv_blocks.begin(); j!=i; ++j)
747 if(rtracks.count((*j)->get_endpoints()[j->entry()].track))
751 signal_route_changed.emit(routes.front().route);
756 // Move blocks up to the next sensor to our current blocks
757 cur_blocks.splice(cur_blocks.end(), rsv_blocks, rsv_blocks.begin(), i);
759 // Try to get more blocks if we're moving
764 layout.emergency("Sensor for "+name+" triggered out of order");
768 const Vehicle &veh = *(reverse ? vehicles.front() : vehicles.back());
770 // Find the first sensor in our current blocks that's still active
771 BlockList::iterator end = cur_blocks.begin();
772 for(BlockList::iterator i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
774 if((*i)->has_track(*veh.get_track()))
776 if((*i)->get_sensor_id())
778 if(layout.get_driver().get_sensor((*i)->get_sensor_id()))
788 if(end!=cur_blocks.begin() && end!=cur_blocks.end())
789 // Free blocks up to the last inactive sensor
790 release_blocks(cur_blocks, cur_blocks.begin(), end);
794 void Train::turnout_event(unsigned addr, bool)
796 if(pending_block && (!pending_block->get_train() || pending_block->get_train()==this))
798 unsigned pending_addr = pending_block->get_turnout_id();
799 bool double_addr = (*pending_block->get_tracks().begin())->get_type().is_double_address();
800 if(addr==pending_addr || (double_addr && addr==pending_addr+1))
810 void Train::halt_event(bool h)
813 accurate_position = false;
816 void Train::block_reserved(const Block &block, const Train *train)
818 if(&block==pending_block && !train && !reserving)
822 unsigned Train::reserve_more()
828 if(!rsv_blocks.empty())
829 start = rsv_blocks.back();
830 else if(!cur_blocks.empty())
831 start = cur_blocks.back();
837 // See how many sensor blocks and how much track we already have
840 for(BlockList::const_iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
842 if((*i)->get_sensor_id())
845 dist += (*i)->get_path_length(i->entry());
851 list<RouteRef>::iterator cur_route = routes.begin();
852 advance_route(cur_route, *start.track_iter());
854 float approach_margin = 50*layout.get_catalogue().get_scale();
855 float min_dist = controller->get_braking_distance()*1.3+approach_margin*2;
857 BlockIter block = start;
858 BlockIter good = start;
859 Track *divert_track = 0;
860 bool try_divert = false;
861 unsigned good_sens = nsens;
862 float good_dist = dist;
863 Train *blocking_train = 0;
864 BlockList contested_blocks;
866 SetFlag setf(reserving);
868 while(good_sens<3 || good_dist<min_dist || !contested_blocks.empty())
870 BlockIter last = block;
871 block = block.next(cur_route!=routes.end() ? cur_route->route : 0);
875 TrackIter track = block.track_iter();
877 if(cur_route!=routes.end())
879 if(!advance_route(cur_route, *track))
881 // Keep the blocks if we arrived at the end of the route
892 else if(!routes.empty() && routes.front().route->has_track(*track))
893 cur_route = routes.begin();
895 if(block->get_endpoints().size()<2)
908 if(block->get_train()!=blocking_train)
910 if(blocking_train->free_block(*contested_blocks.back()))
912 // Roll back and start actually reserving the blocks
913 block = rsv_blocks.back();
914 cur_route = routes.begin();
915 advance_route(cur_route, *block.track_iter().track());
916 if(blocking_train->get_priority()==priority)
917 blocking_train->yield_to(*this);
923 yield_to(*blocking_train);
924 pending_block = contested_blocks.front().block();
925 try_divert = divert_track;
931 contested_blocks.push_back(block);
936 bool reserved = block->reserve(this);
939 /* We've found another train. If it wants to exit the block from the
940 same endpoint we're trying to enter from or the other way around,
941 treat it as coming towards us. Otherwise treat it as going in the
943 Train *other_train = block->get_train();
944 int other_entry = other_train->get_entry_to_block(*block);
946 throw LogicError("Block reservation inconsistency");
948 unsigned exit = block.reverse().entry();
949 unsigned other_exit = BlockIter(block.block(), other_entry).reverse().entry();
950 bool entry_conflict = (block.entry()==other_exit);
951 bool exit_conflict = (exit==static_cast<unsigned>(other_entry));
952 if(!entry_conflict && !last->get_turnout_id())
954 /* The other train is not coming to the blocks we're holding, so we
961 int other_prio = other_train->get_priority();
963 if(!entry_conflict && !exit_conflict && other_prio<priority)
965 /* Ask a lesser priority train going to the same direction to free
967 if(other_train->free_block(*block))
968 reserved = block->reserve(this);
970 else if(other_train!=yielding_to && (other_prio<priority || (other_prio==priority && entry_conflict)))
972 /* A lesser priority train is coming at us, we must ask it to free
973 enough blocks to get clear of it to avoid a potential deadlock */
974 blocking_train = other_train;
975 contested_blocks.clear();
976 contested_blocks.push_back(block);
979 else if(divert_track && (entry_conflict || exit_conflict))
980 // We are blocked, but there's a diversion possibility
985 pending_block = &*block;
990 if(block->get_turnout_id())
992 const TrackType::Endpoint &track_ep = track->get_type().get_endpoints()[track.entry()];
993 bool multiple_paths = (track_ep.paths&(track_ep.paths-1));
995 if(multiple_paths || !last->get_turnout_id())
997 /* We can keep the blocks reserved so far if we are facing the
998 points or if there was no turnout immediately before this one.
999 With multiple successive turnouts (as is common in crossovers) it's
1000 best to hold at one we can divert from. */
1006 // Figure out what path we'd like to take on the turnout
1008 for(list<RouteRef>::iterator i=cur_route; (path<0 && i!=routes.end()); ++i)
1009 path = i->route->get_turnout(block->get_turnout_id());
1011 path = track->get_active_path();
1012 if(!(track_ep.paths&(1<<path)))
1014 for(unsigned i=0; track_ep.paths>>i; ++i)
1015 if(track_ep.paths&(1<<i))
1019 if(path!=static_cast<int>(track->get_active_path()))
1021 // The turnout is set to wrong path - switch and wait for it
1022 pending_block = &*block;
1023 track->set_active_path(path);
1031 if(multiple_paths && cur_route!=routes.end() && cur_route->diversion!=block->get_turnout_id())
1032 /* There's multiple paths to be taken and we are on a route - take
1033 note of the diversion possibility */
1034 divert_track = &*track;
1037 if(!contested_blocks.empty() && contested_blocks.front()==block)
1038 contested_blocks.pop_front();
1040 rsv_blocks.push_back(block);
1041 if(block->get_sensor_id())
1044 dist += block->get_path_length(block.entry());
1047 // Unreserve blocks that were not good
1048 while(!rsv_blocks.empty() && rsv_blocks.back()!=good)
1050 rsv_blocks.back()->reserve(0);
1051 rsv_blocks.pop_back();
1054 if(!rsv_blocks.empty() && rsv_blocks.back()!=start)
1055 // We got some new blocks, so no longer need to yield
1058 // Make any sensorless blocks at the beginning immediately current
1059 BlockList::iterator i;
1060 for(i=rsv_blocks.begin(); (i!=rsv_blocks.end() && !(*i)->get_sensor_id()); ++i) ;
1061 if(i!=rsv_blocks.begin())
1062 cur_blocks.splice(cur_blocks.end(), rsv_blocks, rsv_blocks.begin(), i);
1064 if(try_divert && divert(*divert_track))
1065 return reserve_more();
1070 float Train::get_reserved_distance_until(const Block *until_block, bool back) const
1072 if(cur_blocks.empty())
1075 Vehicle &veh = *(reverse!=back ? vehicles.back() : vehicles.front());
1076 const VehicleType &vtype = veh.get_type();
1078 TrackIter track(veh.get_track(), veh.get_entry());
1082 BlockList::const_iterator block = cur_blocks.begin();
1083 while(block!=rsv_blocks.end() && !(*block)->has_track(*track))
1086 if(block==cur_blocks.end())
1090 block = rsv_blocks.begin();
1093 if(block==rsv_blocks.end() || &**block==until_block)
1096 float result = veh.get_offset();
1098 track = track.reverse();
1100 result = track->get_type().get_path_length(track->get_active_path())-result;
1101 result -= vtype.get_length()/2;
1105 track = track.next();
1109 if(!(*block)->has_track(*track))
1113 if(block==cur_blocks.begin())
1120 if(block==cur_blocks.end())
1121 block = rsv_blocks.begin();
1122 if(block==rsv_blocks.end())
1126 if(&**block==until_block)
1130 result += track->get_type().get_path_length(track->get_active_path());
1136 float Train::get_real_speed(unsigned i) const
1138 if(real_speed[i].weight)
1139 return real_speed[i].speed;
1143 for(low=i; low>0; --low)
1144 if(real_speed[low].weight)
1146 for(high=i; high<14; ++high)
1147 if(real_speed[high].weight)
1150 if(real_speed[high].weight)
1152 if(real_speed[low].weight)
1154 float f = float(i-low)/(high-low);
1155 return real_speed[low].speed*(1-f)+real_speed[high].speed*f;
1158 return real_speed[high].speed*float(i)/high;
1160 else if(real_speed[low].weight)
1161 return real_speed[low].speed*float(i)/low;
1166 unsigned Train::find_speed(float real) const
1168 if(real<=real_speed[0].speed)
1174 for(unsigned i=0; (!high && i<=14); ++i)
1175 if(real_speed[i].weight)
1178 if(real_speed[i].speed<real)
1192 return min(min(static_cast<unsigned>(low*real/real_speed[low].speed), 14U), last+3);
1195 float f = (real-real_speed[low].speed)/(real_speed[high].speed-real_speed[low].speed);
1196 return static_cast<unsigned>(low*(1-f)+high*f+0.5);
1199 float Train::get_travel_speed() const
1201 float speed = get_real_speed(current_speed);
1202 float scale = layout.get_catalogue().get_scale();
1203 return static_cast<int>(round(speed/scale*3.6/5))*5;
1206 void Train::set_status(const string &s)
1209 signal_status_changed.emit(s);
1212 void Train::release_blocks(BlockList &blocks)
1214 release_blocks(blocks, blocks.begin(), blocks.end());
1217 void Train::release_blocks(BlockList &blocks, BlockList::iterator begin, BlockList::iterator end)
1221 Block &block = **begin;
1222 blocks.erase(begin++);
1227 void Train::reverse_blocks(BlockList &blocks) const
1230 for(BlockList::iterator i=blocks.begin(); i!=blocks.end(); ++i)
1234 bool Train::advance_route(list<RouteRef>::iterator &iter, Track &track)
1236 while(iter!=routes.end() && !iter->route->has_track(track))
1238 if(iter==routes.end())
1241 list<RouteRef>::iterator next = iter;
1243 if(next!=routes.end() && next->diversion && next->route->has_track(track))
1249 Route *Train::create_lead_route(Route *lead, const Route *target)
1253 lead = new Route(layout);
1254 lead->set_name("Lead");
1255 lead->set_temporary(true);
1258 set<Track *> tracks;
1259 for(BlockList::iterator i=cur_blocks.begin(); i!=rsv_blocks.end(); )
1261 const set<Track *> &btracks = (*i)->get_tracks();
1262 for(set<Track *>::const_iterator j=btracks.begin(); j!=btracks.end(); ++j)
1263 if(!target || !target->has_track(**j))
1266 if(++i==cur_blocks.end())
1267 i = rsv_blocks.begin();
1270 lead->add_tracks(tracks);
1275 bool Train::is_valid_diversion(const Route &diversion, Track &from, unsigned from_ep)
1277 float diversion_len = 0;
1278 TrackIter track(&from, from_ep);
1279 while(diversion.has_track(*track))
1281 unsigned tid = track->get_turnout_id();
1282 unsigned path = (tid ? diversion.get_turnout(tid) : 0);
1283 diversion_len += track->get_type().get_path_length(path);
1285 track = track.next(path);
1291 list<RouteRef>::iterator route = routes.begin();
1292 if(!advance_route(route, from))
1295 set<Track *> visited;
1296 float route_len = 0;
1297 track = TrackIter(&from, from_ep);
1300 unsigned tid = track->get_turnout_id();
1301 unsigned path = (tid ? route->route->get_turnout(tid) : 0);
1302 route_len += track->get_type().get_path_length(path);
1304 if(&*track!=&from && diversion.has_track(*track))
1307 if(visited.count(&*track))
1309 visited.insert(&*track);
1311 track = track.next(path);
1313 if(!advance_route(route, *track))
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(unsigned n)
1436 const VehicleType &vtype = obj.layout.get_catalogue().get_vehicle(n);
1437 Vehicle *veh = new Vehicle(obj.layout, vtype);
1438 obj.vehicles.back()->attach_back(*veh);
1439 obj.vehicles.push_back(veh);
1442 } // namespace Marklin