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");
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);
318 for(list<RouteRef>::iterator i=routes.begin(); i!=routes.end(); ++i)
319 tracks.insert(i->route->get_tracks().begin(), i->route->get_tracks().end());
320 RefPtr<Route> diversion = Route::find(track, tracks);
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))
331 // Follow the diversion route until we get back to the original route
332 list<RouteRef>::iterator end = routes.end();
335 for(list<RouteRef>::iterator i=route; (end==routes.end() && i!=routes.end()); ++i)
336 if(i->route->has_track(*track))
339 if(end!=routes.end())
341 else if(!diversion->has_track(*track))
342 throw LogicError("Pathfinder returned a bad route");
344 unsigned tid = track->get_turnout_id();
345 track = track.next(tid ? diversion->get_turnout(tid) : 0);
349 // We are rejoining the same route we diverted from, duplicate it
350 routes.insert(end, *route);
354 routes.erase(route, end);
356 routes.insert(end, RouteRef(diversion.release(), from.get_turnout_id()));
361 const Route *Train::get_route() const
365 return routes.front().route;
368 void Train::place(Block &block, unsigned entry)
370 if(controller->get_speed())
371 throw InvalidState("Must be stopped before placing");
373 release_blocks(rsv_blocks);
374 release_blocks(cur_blocks);
377 accurate_position = false;
379 if(!block.reserve(this))
381 set_status("Unplaced");
385 cur_blocks.push_back(BlockIter(&block, entry));
388 TrackIter track = BlockIter(&block, entry).reverse().track_iter();
389 vehicles.front()->place(*track, track.entry(), 0, Vehicle::FRONT_BUFFER);
393 const Block::Endpoint &bep = block.get_endpoints()[entry];
394 vehicles.back()->place(*bep.track, bep.track_ep, 0, Vehicle::BACK_BUFFER);
398 void Train::unplace()
400 if(controller->get_speed())
401 throw InvalidState("Must be stopped before unplacing");
403 release_blocks(rsv_blocks);
404 release_blocks(cur_blocks);
407 accurate_position = false;
409 for(vector<Vehicle *>::iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
412 set_status("Unplaced");
415 bool Train::free_block(Block &block)
417 float margin = 10*layout.get_catalogue().get_scale();
418 if(get_reserved_distance_until(&block, false)<controller->get_braking_distance()*1.3+margin)
422 for(BlockList::iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
424 if(i->block()==&block)
428 release_blocks(rsv_blocks, i, rsv_blocks.end());
431 else if((*i)->get_sensor_id())
438 void Train::free_noncritical_blocks()
440 if(cur_blocks.empty() || rsv_blocks.empty())
443 if(controller->get_speed()==0)
445 release_blocks(rsv_blocks);
449 float margin = 10*layout.get_catalogue().get_scale();
450 float min_dist = controller->get_braking_distance()*1.3+margin;
452 Vehicle &veh = *(reverse ? vehicles.back() : vehicles.front());
454 TrackIter track(veh.get_track(), veh.get_entry());
455 BlockList::iterator block = cur_blocks.begin();
457 while(block!=rsv_blocks.end() && !(*block)->has_track(*track))
460 if(block==cur_blocks.end())
462 block = rsv_blocks.begin();
467 float dist = veh.get_offset();
471 dist = track->get_type().get_path_length(track->get_active_path())-dist;
472 dist -= veh.get_type().get_length()/2;
477 track = track.next();
479 if(!(*block)->has_track(*track))
482 if(block==cur_blocks.end())
484 block = rsv_blocks.begin();
487 if(block==rsv_blocks.end())
490 if(dist>min_dist && nsens>0)
492 release_blocks(rsv_blocks, block, rsv_blocks.end());
496 if(in_rsv && (*block)->get_sensor_id())
500 dist += track->get_type().get_path_length(track->get_active_path());
504 int Train::get_entry_to_block(Block &block) const
506 for(BlockList::const_iterator i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
507 if(i->block()==&block)
509 for(BlockList::const_iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
510 if(i->block()==&block)
515 float Train::get_reserved_distance() const
517 return get_reserved_distance_until(0, false);
520 void Train::tick(const Time::TimeStamp &t, const Time::TimeDelta &dt)
522 if(!active && stop_timeout && t>=stop_timeout)
524 release_blocks(rsv_blocks);
525 end_of_route = false;
526 stop_timeout = Time::TimeStamp();
529 Driver &driver = layout.get_driver();
533 controller->tick(dt);
534 float speed = controller->get_speed();
535 unsigned speed_notch = find_speed(speed);
537 if(controller->get_reverse()!=reverse)
539 reverse = controller->get_reverse();
540 driver.set_loco_reverse(address, reverse);
542 release_blocks(rsv_blocks);
543 reverse_blocks(cur_blocks);
547 if(speed_notch!=current_speed && !speed_changing && !driver.is_halted() && driver.get_power())
549 speed_changing = true;
550 driver.set_loco_speed(address, speed_notch);
555 set_status(format("Traveling %d kmh", get_travel_speed()));
557 set_status("Waiting");
565 Vehicle &vehicle = *(reverse ? vehicles.back() : vehicles.front());
566 Track *track = vehicle.get_track();
569 for(BlockList::const_iterator i=cur_blocks.begin(); (!ok && i!=cur_blocks.end()); ++i)
570 ok = (*i)->has_track(*track);
572 float d = get_real_speed(current_speed)*(dt/Time::sec);
575 SetFlag setf(advancing);
576 vehicle.advance(reverse ? -d : d);
578 else if(accurate_position)
581 if(overshoot_dist>40*layout.get_catalogue().get_scale())
583 layout.emergency(name+" has not arrived at sensor");
584 accurate_position = false;
588 else if(end_of_route && rsv_blocks.empty())
591 signal_arrived.emit();
595 if(!cur_blocks.empty() && !cur_blocks.front()->get_sensor_id())
597 float dist = get_reserved_distance_until(&*cur_blocks.front(), true);
599 if(dist>10*layout.get_catalogue().get_scale())
601 cur_blocks.front()->reserve(0);
602 cur_blocks.pop_front();
607 void Train::save(list<DataFile::Statement> &st) const
609 st.push_back((DataFile::Statement("name"), name));
611 st.push_back((DataFile::Statement("priority"), priority));
613 for(vector<Vehicle *>::const_iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
614 if(i!=vehicles.begin())
615 st.push_back((DataFile::Statement("vehicle"), (*i)->get_type().get_article_number()));
617 for(unsigned i=0; i<=14; ++i)
618 if(real_speed[i].weight)
619 st.push_back((DataFile::Statement("real_speed"), i, real_speed[i].speed, real_speed[i].weight));
621 if(!cur_blocks.empty())
623 BlockList blocks = cur_blocks;
625 reverse_blocks(blocks);
627 BlockIter prev = blocks.front().flip();
628 st.push_back((DataFile::Statement("block_hint"), prev->get_id()));
630 for(BlockList::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
631 st.push_back((DataFile::Statement("block"), (*i)->get_id()));
636 list<RouteRef>::const_iterator i = routes.begin();
637 for(; (i!=routes.end() && i->route->is_temporary()); ++i) ;
639 st.push_back((DataFile::Statement("route"), i->route->get_name()));
644 DataFile::Statement ss("timetable");
645 timetable->save(ss.sub);
650 void Train::control_changed(const Controller::Control &ctrl)
652 signal_control_changed.emit(ctrl.name, ctrl.value);
655 void Train::loco_speed_event(unsigned addr, unsigned speed, bool)
659 current_speed = speed;
660 speed_changing = false;
665 void Train::loco_func_event(unsigned addr, unsigned func, bool state)
667 if(addr==address || (addr==address+1 && loco_type.get_max_function()>4))
672 functions |= 1<<func;
674 functions &= ~(1<<func);
676 signal_function_changed.emit(func, state);
680 void Train::sensor_event(unsigned addr, bool state)
684 // Find the first sensor block from our reserved blocks that isn't this sensor
685 BlockList::iterator i;
687 for(i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
688 if((*i)->get_sensor_id())
690 if((*i)->get_sensor_id()!=addr)
703 if(result==1 && i!=rsv_blocks.begin())
705 // Compute speed and update related state
706 float travel_time_secs = (Time::now()-last_entry_time)/Time::sec;
712 RealSpeed &rs = real_speed[current_speed];
713 rs.add(travel_dist/travel_time_secs, travel_time_secs);
715 set_status(format("Traveling %d kmh", get_travel_speed()));
719 for(BlockList::iterator j=rsv_blocks.begin(); j!=i; ++j)
721 travel_dist += (*j)->get_path_length(j->entry());
723 if((*j)->get_sensor_id()==addr && !advancing)
725 TrackIter track = j->track_iter();
728 track = track.flip();
729 vehicles.back()->place(*track, track.entry(), 0, Vehicle::BACK_AXLE);
732 vehicles.front()->place(*track, track.entry(), 0, Vehicle::FRONT_AXLE);
735 last_entry_time = Time::now();
737 accurate_position = true;
740 // Check if we've reached the next route
743 const set<Track *> &rtracks = (++routes.begin())->route->get_tracks();
744 for(BlockList::iterator j=rsv_blocks.begin(); j!=i; ++j)
745 if(rtracks.count((*j)->get_endpoints()[j->entry()].track))
749 signal_route_changed.emit(routes.front().route);
754 // Move blocks up to the next sensor to our current blocks
755 cur_blocks.splice(cur_blocks.end(), rsv_blocks, rsv_blocks.begin(), i);
757 // Try to get more blocks if we're moving
762 layout.emergency("Sensor for "+name+" triggered out of order");
766 const Vehicle &veh = *(reverse ? vehicles.front() : vehicles.back());
768 // Find the first sensor in our current blocks that's still active
769 BlockList::iterator end = cur_blocks.begin();
770 for(BlockList::iterator i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
772 if((*i)->has_track(*veh.get_track()))
774 if((*i)->get_sensor_id())
776 if(layout.get_driver().get_sensor((*i)->get_sensor_id()))
786 if(end!=cur_blocks.begin() && end!=cur_blocks.end())
787 // Free blocks up to the last inactive sensor
788 release_blocks(cur_blocks, cur_blocks.begin(), end);
792 void Train::turnout_event(unsigned addr, bool)
794 if(pending_block && (!pending_block->get_train() || pending_block->get_train()==this))
796 unsigned pending_addr = pending_block->get_turnout_id();
797 bool double_addr = (*pending_block->get_tracks().begin())->get_type().is_double_address();
798 if(addr==pending_addr || (double_addr && addr==pending_addr+1))
808 void Train::halt_event(bool h)
811 accurate_position = false;
814 void Train::block_reserved(const Block &block, const Train *train)
816 if(&block==pending_block && !train && !reserving)
820 unsigned Train::reserve_more()
826 if(!rsv_blocks.empty())
827 start = rsv_blocks.back();
828 else if(!cur_blocks.empty())
829 start = cur_blocks.back();
835 // See how many sensor blocks and how much track we already have
838 for(BlockList::const_iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
840 if((*i)->get_sensor_id())
843 dist += (*i)->get_path_length(i->entry());
849 list<RouteRef>::iterator cur_route = routes.begin();
850 advance_route(cur_route, *start.track_iter());
852 float approach_margin = 50*layout.get_catalogue().get_scale();
853 float min_dist = controller->get_braking_distance()*1.3+approach_margin*2;
855 BlockIter block = start;
856 BlockIter good = start;
857 Track *divert_track = 0;
858 bool try_divert = false;
859 unsigned good_sens = nsens;
860 float good_dist = dist;
861 Train *blocking_train = 0;
862 BlockList contested_blocks;
864 SetFlag setf(reserving);
866 while(good_sens<3 || good_dist<min_dist || !contested_blocks.empty())
868 BlockIter last = block;
869 block = block.next(cur_route!=routes.end() ? cur_route->route : 0);
873 TrackIter track = block.track_iter();
875 if(cur_route!=routes.end())
877 if(!advance_route(cur_route, *track))
879 // Keep the blocks if we arrived at the end of the route
890 else if(!routes.empty() && routes.front().route->has_track(*track))
891 cur_route = routes.begin();
893 if(block->get_endpoints().size()<2)
906 if(block->get_train()!=blocking_train)
908 if(blocking_train->free_block(*contested_blocks.back()))
910 // Roll back and start actually reserving the blocks
911 block = rsv_blocks.back();
912 cur_route = routes.begin();
913 advance_route(cur_route, *block.track_iter().track());
914 if(blocking_train->get_priority()==priority)
915 blocking_train->yield_to(*this);
921 yield_to(*blocking_train);
922 pending_block = contested_blocks.front().block();
923 try_divert = divert_track;
929 contested_blocks.push_back(block);
934 bool reserved = block->reserve(this);
937 /* We've found another train. If it wants to exit the block from the
938 same endpoint we're trying to enter from or the other way around,
939 treat it as coming towards us. Otherwise treat it as going in the
941 Train *other_train = block->get_train();
942 int other_entry = other_train->get_entry_to_block(*block);
944 throw LogicError("Block reservation inconsistency");
946 unsigned exit = block.reverse().entry();
947 unsigned other_exit = BlockIter(block.block(), other_entry).reverse().entry();
948 bool entry_conflict = (block.entry()==other_exit);
949 bool exit_conflict = (exit==static_cast<unsigned>(other_entry));
950 if(!entry_conflict && !last->get_turnout_id())
952 /* The other train is not coming to the blocks we're holding, so we
959 int other_prio = other_train->get_priority();
961 if(!entry_conflict && !exit_conflict && other_prio<priority)
963 /* Ask a lesser priority train going to the same direction to free
965 if(other_train->free_block(*block))
966 reserved = block->reserve(this);
968 else if(other_train!=yielding_to && (other_prio<priority || (other_prio==priority && entry_conflict)))
970 /* A lesser priority train is coming at us, we must ask it to free
971 enough blocks to get clear of it to avoid a potential deadlock */
972 blocking_train = other_train;
973 contested_blocks.clear();
974 contested_blocks.push_back(block);
977 else if(divert_track && (entry_conflict || exit_conflict))
978 // We are blocked, but there's a diversion possibility
983 pending_block = &*block;
988 if(block->get_turnout_id())
990 const TrackType::Endpoint &track_ep = track->get_type().get_endpoints()[track.entry()];
991 bool multiple_paths = (track_ep.paths&(track_ep.paths-1));
993 if(multiple_paths || !last->get_turnout_id())
995 /* We can keep the blocks reserved so far if we are facing the
996 points or if there was no turnout immediately before this one.
997 With multiple successive turnouts (as is common in crossovers) it's
998 best to hold at one we can divert from. */
1004 // Figure out what path we'd like to take on the turnout
1006 for(list<RouteRef>::iterator i=cur_route; (path<0 && i!=routes.end()); ++i)
1007 path = i->route->get_turnout(block->get_turnout_id());
1009 path = track->get_active_path();
1010 if(!(track_ep.paths&(1<<path)))
1012 for(unsigned i=0; track_ep.paths>>i; ++i)
1013 if(track_ep.paths&(1<<i))
1017 if(path!=static_cast<int>(track->get_active_path()))
1019 // The turnout is set to wrong path - switch and wait for it
1020 pending_block = &*block;
1021 track->set_active_path(path);
1029 if(multiple_paths && cur_route!=routes.end() && cur_route->diversion!=block->get_turnout_id())
1030 /* There's multiple paths to be taken and we are on a route - take
1031 note of the diversion possibility */
1032 divert_track = &*track;
1035 if(!contested_blocks.empty() && contested_blocks.front()==block)
1036 contested_blocks.pop_front();
1038 rsv_blocks.push_back(block);
1039 if(block->get_sensor_id())
1042 dist += block->get_path_length(block.entry());
1045 // Unreserve blocks that were not good
1046 while(!rsv_blocks.empty() && rsv_blocks.back()!=good)
1048 rsv_blocks.back()->reserve(0);
1049 rsv_blocks.pop_back();
1052 if(!rsv_blocks.empty() && rsv_blocks.back()!=start)
1053 // We got some new blocks, so no longer need to yield
1056 // Make any sensorless blocks at the beginning immediately current
1057 BlockList::iterator i;
1058 for(i=rsv_blocks.begin(); (i!=rsv_blocks.end() && !(*i)->get_sensor_id()); ++i) ;
1059 if(i!=rsv_blocks.begin())
1060 cur_blocks.splice(cur_blocks.end(), rsv_blocks, rsv_blocks.begin(), i);
1062 if(try_divert && divert(*divert_track))
1063 return reserve_more();
1068 float Train::get_reserved_distance_until(const Block *until_block, bool back) const
1070 if(cur_blocks.empty())
1073 Vehicle &veh = *(reverse!=back ? vehicles.back() : vehicles.front());
1074 const VehicleType &vtype = veh.get_type();
1076 TrackIter track(veh.get_track(), veh.get_entry());
1080 BlockList::const_iterator block = cur_blocks.begin();
1081 while(block!=rsv_blocks.end() && !(*block)->has_track(*track))
1084 if(block==cur_blocks.end())
1088 block = rsv_blocks.begin();
1091 if(block==rsv_blocks.end() || &**block==until_block)
1094 float result = veh.get_offset();
1096 track = track.reverse();
1098 result = track->get_type().get_path_length(track->get_active_path())-result;
1099 result -= vtype.get_length()/2;
1103 track = track.next();
1107 if(!(*block)->has_track(*track))
1111 if(block==cur_blocks.begin())
1118 if(block==cur_blocks.end())
1119 block = rsv_blocks.begin();
1120 if(block==rsv_blocks.end())
1124 if(&**block==until_block)
1128 result += track->get_type().get_path_length(track->get_active_path());
1134 float Train::get_real_speed(unsigned i) const
1136 if(real_speed[i].weight)
1137 return real_speed[i].speed;
1141 for(low=i; low>0; --low)
1142 if(real_speed[low].weight)
1144 for(high=i; high<14; ++high)
1145 if(real_speed[high].weight)
1148 if(real_speed[high].weight)
1150 if(real_speed[low].weight)
1152 float f = float(i-low)/(high-low);
1153 return real_speed[low].speed*(1-f)+real_speed[high].speed*f;
1156 return real_speed[high].speed*float(i)/high;
1158 else if(real_speed[low].weight)
1159 return real_speed[low].speed*float(i)/low;
1164 unsigned Train::find_speed(float real) const
1166 if(real<=real_speed[0].speed)
1172 for(unsigned i=0; (!high && i<=14); ++i)
1173 if(real_speed[i].weight)
1176 if(real_speed[i].speed<real)
1190 return min(min(static_cast<unsigned>(low*real/real_speed[low].speed), 14U), last+3);
1193 float f = (real-real_speed[low].speed)/(real_speed[high].speed-real_speed[low].speed);
1194 return static_cast<unsigned>(low*(1-f)+high*f+0.5);
1197 float Train::get_travel_speed() const
1199 float speed = get_real_speed(current_speed);
1200 float scale = layout.get_catalogue().get_scale();
1201 return static_cast<int>(round(speed/scale*3.6/5))*5;
1204 void Train::set_status(const string &s)
1207 signal_status_changed.emit(s);
1210 void Train::release_blocks(BlockList &blocks)
1212 release_blocks(blocks, blocks.begin(), blocks.end());
1215 void Train::release_blocks(BlockList &blocks, BlockList::iterator begin, BlockList::iterator end)
1219 Block &block = **begin;
1220 blocks.erase(begin++);
1225 void Train::reverse_blocks(BlockList &blocks) const
1228 for(BlockList::iterator i=blocks.begin(); i!=blocks.end(); ++i)
1232 bool Train::advance_route(list<RouteRef>::iterator &iter, Track &track)
1234 while(iter!=routes.end() && !iter->route->has_track(track))
1236 if(iter==routes.end())
1239 list<RouteRef>::iterator next = iter;
1241 if(next!=routes.end() && next->diversion && next->route->has_track(track))
1247 Route *Train::create_lead_route(Route *lead, const Route *target)
1251 lead = new Route(layout);
1252 lead->set_name("Lead");
1253 lead->set_temporary(true);
1256 set<Track *> tracks;
1257 for(BlockList::iterator i=cur_blocks.begin(); i!=rsv_blocks.end(); )
1259 const set<Track *> &btracks = (*i)->get_tracks();
1260 for(set<Track *>::const_iterator j=btracks.begin(); j!=btracks.end(); ++j)
1261 if(!target || !target->has_track(**j))
1264 if(++i==cur_blocks.end())
1265 i = rsv_blocks.begin();
1268 lead->add_tracks(tracks);
1273 bool Train::is_valid_diversion(const Route &diversion, Track &from, unsigned from_ep)
1275 float diversion_len = 0;
1276 TrackIter track(&from, from_ep);
1277 while(diversion.has_track(*track))
1279 unsigned tid = track->get_turnout_id();
1280 unsigned path = (tid ? diversion.get_turnout(tid) : 0);
1281 diversion_len += track->get_type().get_path_length(path);
1283 track = track.next(path);
1289 list<RouteRef>::iterator route = routes.begin();
1290 if(!advance_route(route, from))
1293 set<Track *> visited;
1294 float route_len = 0;
1295 track = TrackIter(&from, from_ep);
1298 unsigned tid = track->get_turnout_id();
1299 unsigned path = (tid ? route->route->get_turnout(tid) : 0);
1300 route_len += track->get_type().get_path_length(path);
1302 if(&*track!=&from && diversion.has_track(*track))
1305 if(visited.count(&*track))
1307 visited.insert(&*track);
1309 track = track.next(path);
1311 if(!advance_route(route, *track))
1315 return diversion_len<route_len*1.2;
1319 Train::RouteRef::RouteRef(const Route *r, unsigned d):
1325 Train::RealSpeed::RealSpeed():
1330 void Train::RealSpeed::add(float s, float w)
1332 speed = (speed*weight+s*w)/(weight+w);
1333 weight = min(weight+w, 300.0f);
1337 Train::Loader::Loader(Train &t):
1338 DataFile::BasicLoader<Train>(t),
1342 add("block", &Loader::block);
1343 add("block_hint", &Loader::block_hint);
1344 add("name", &Loader::name);
1345 add("priority", &Train::priority);
1346 add("real_speed", &Loader::real_speed);
1347 add("route", &Loader::route);
1348 add("timetable", &Loader::timetable);
1349 add("vehicle", &Loader::vehicle);
1352 void Train::Loader::finish()
1354 if(!obj.cur_blocks.empty())
1356 TrackIter track = obj.cur_blocks.front().track_iter();
1357 float offset = 2*obj.layout.get_catalogue().get_scale();
1358 obj.vehicles.back()->place(*track, track.entry(), offset, Vehicle::BACK_BUFFER);
1360 obj.set_status("Stopped");
1364 void Train::Loader::block(unsigned id)
1372 blk = &obj.layout.get_block(id);
1374 catch(const KeyError &)
1376 blocks_valid = false;
1382 entry = blk->get_endpoint_by_link(*prev_block);
1387 obj.cur_blocks.push_back(BlockIter(blk, entry));
1389 if(blk->get_sensor_id())
1390 obj.layout.get_driver().set_sensor(blk->get_sensor_id(), true);
1395 void Train::Loader::block_hint(unsigned id)
1399 prev_block = &obj.layout.get_block(id);
1401 catch(const KeyError &)
1403 blocks_valid = false;
1407 void Train::Loader::name(const string &n)
1412 void Train::Loader::real_speed(unsigned i, float speed, float weight)
1414 obj.real_speed[i].speed = speed;
1415 obj.real_speed[i].weight = weight;
1418 void Train::Loader::route(const string &n)
1420 obj.set_route(&obj.layout.get_route(n));
1423 void Train::Loader::timetable()
1426 throw InvalidState("A timetable has already been loaded");
1428 obj.timetable = new Timetable(obj);
1429 load_sub(*obj.timetable);
1432 void Train::Loader::vehicle(ArticleNumber art_nr)
1434 const VehicleType &vtype = obj.layout.get_catalogue().get_vehicle(art_nr);
1435 Vehicle *veh = new Vehicle(obj.layout, vtype);
1436 obj.vehicles.back()->attach_back(*veh);
1437 obj.vehicles.push_back(veh);
1440 } // namespace Marklin