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):
49 cur_blocks_end(blocks.end()),
50 clear_blocks_end(blocks.end()),
54 controller(new AIControl(*this, new SimpleController)),
58 speed_changing(false),
66 accurate_position(false),
69 if(!loco_type.is_locomotive())
70 throw InvalidParameterValue("Initial vehicle must be a locomotive");
72 vehicles.push_back(new Vehicle(layout, loco_type));
74 layout.add_train(*this);
76 layout.get_driver().add_loco(address);
77 layout.get_driver().signal_loco_speed.connect(sigc::mem_fun(this, &Train::loco_speed_event));
78 layout.get_driver().signal_loco_function.connect(sigc::mem_fun(this, &Train::loco_func_event));
80 layout.signal_block_reserved.connect(sigc::mem_fun(this, &Train::block_reserved));
81 layout.get_driver().signal_sensor.connect(sigc::mem_fun(this, &Train::sensor_event));
83 layout.get_driver().signal_halt.connect(sigc::mem_fun(this, &Train::halt_event));
85 const set<Track *> &tracks = layout.get_tracks();
86 for(set<Track *>::const_iterator i=tracks.begin(); i!=tracks.end(); ++i)
87 if((*i)->get_turnout_id())
88 (*i)->signal_path_changed.connect(sigc::hide(sigc::bind(sigc::mem_fun(this, &Train::turnout_path_changed), sigc::ref(**i))));
90 controller->signal_control_changed.connect(sigc::mem_fun(this, &Train::control_changed));
97 for(vector<Vehicle *>::iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
99 layout.remove_train(*this);
102 void Train::set_name(const string &n)
106 signal_name_changed.emit(name);
109 void Train::set_priority(int p)
114 void Train::yield_to(const Train &t)
119 void Train::add_vehicle(const VehicleType &vt)
121 Vehicle *veh = new Vehicle(layout, vt);
122 vehicles.back()->attach_back(*veh);
123 vehicles.push_back(veh);
126 void Train::remove_vehicle(unsigned i)
128 if(i>=vehicles.size())
129 throw InvalidParameterValue("Vehicle index out of range");
131 throw InvalidParameterValue("Can't remove the locomotive");
133 vehicles.erase(vehicles.begin()+i);
134 if(i<vehicles.size())
135 vehicles[i-1]->attach_back(*vehicles[i]);
138 unsigned Train::get_n_vehicles() const
140 return vehicles.size();
143 Vehicle &Train::get_vehicle(unsigned i)
145 if(i>=vehicles.size())
146 throw InvalidParameterValue("Vehicle index out of range");
150 const Vehicle &Train::get_vehicle(unsigned i) const
152 if(i>=vehicles.size())
153 throw InvalidParameterValue("Vehicle index out of range");
157 void Train::set_control(const string &n, float v)
159 controller->set_control(n, v);
162 void Train::set_active(bool a)
166 if(!a && controller->get_speed())
167 throw InvalidState("Can't deactivate while moving");
172 stop_timeout = Time::TimeStamp();
177 stop_timeout = Time::now()+2*Time::sec;
178 set_status("Stopped");
182 void Train::set_function(unsigned func, bool state)
184 if(!loco_type.get_functions().count(func))
185 throw InvalidParameterValue("Invalid function");
187 layout.get_driver().set_loco_function(address, func, state);
189 layout.get_driver().set_loco_function(address+1, func-4, state);
192 float Train::get_control(const string &ctrl) const
194 return controller->get_control(ctrl).value;
197 float Train::get_speed() const
199 return controller->get_speed();
202 bool Train::get_function(unsigned func) const
204 return (functions>>func)&1;
207 void Train::set_timetable(Timetable *tt)
213 bool Train::set_route(const Route *r)
215 free_noncritical_blocks();
218 if(r && !blocks.empty())
220 TrackIter first = blocks.front().track_iter();
221 TrackIter next = blocks.back().next().track_iter();
222 if(!r->has_track(*next))
224 lead = Route::find(next, *r);
227 create_lead_route(lead, lead);
228 routes.push_front(lead);
230 else if(!r->has_track(*first))
231 lead = create_lead_route(0, r);
236 routes.push_back(lead);
239 end_of_route = false;
243 signal_route_changed.emit(get_route());
248 bool Train::go_to(Track &to)
250 for(BlockList::const_iterator i=blocks.begin(); i!=cur_blocks_end; ++i)
251 if((*i)->has_track(to))
253 signal_arrived.emit();
257 free_noncritical_blocks();
259 TrackIter next = blocks.back().next().track_iter();
261 Route *route = Route::find(next, to);
264 create_lead_route(route, route);
265 return set_route(route);
268 bool Train::divert(Track &from)
270 if(!from.get_turnout_id())
271 throw InvalidParameterValue("Can't divert from a non-turnout");
277 list<RouteRef>::iterator route = routes.begin();
279 // Follow our routes to find out where we're entering the turnout
280 for(TrackLoopIter track = blocks.front().track_iter();;)
282 if(!advance_route(route, *track))
287 Block &block = track->get_block();
288 if(block.get_train()==this && !free_block(block))
291 int route_path = route->route->get_turnout(from.get_turnout_id());
293 // Check that more than one path is available
294 unsigned ep_paths = track->get_type().get_endpoints()[track.entry()].paths;
295 if(!(ep_paths&(ep_paths-1)))
298 // Choose some other path
299 for(int i=0; ep_paths>>i; ++i)
300 if((ep_paths&(1<<i)) && i!=route_path)
306 entry = track.entry();
310 track = track.next(route->route->get_path(*track));
312 if(!track || track.looped())
316 TrackIter track = TrackIter(&from, entry).next(path);
321 for(list<RouteRef>::iterator i=routes.begin(); i!=routes.end(); ++i)
322 tracks.insert(i->route->get_tracks().begin(), i->route->get_tracks().end());
323 RefPtr<Route> diversion = Route::find(track, tracks);
327 diversion->set_name("Diversion");
328 diversion->add_track(from);
329 diversion->set_turnout(from.get_turnout_id(), path);
331 if(!is_valid_diversion(*diversion, TrackIter(&from, entry)))
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 LogicError("Pathfinder returned a bad route");
347 track = track.next(diversion->get_path(*track));
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");
378 accurate_position = false;
380 if(!block.reserve(this))
382 set_status("Unplaced");
386 blocks.push_back(BlockIter(&block, entry));
389 TrackIter track = BlockIter(&block, entry).reverse().track_iter();
390 vehicles.front()->place(*track, track.entry(), 0, Vehicle::FRONT_BUFFER);
394 const Block::Endpoint &bep = block.get_endpoints()[entry];
395 vehicles.back()->place(*bep.track, bep.track_ep, 0, Vehicle::BACK_BUFFER);
399 void Train::unplace()
401 if(controller->get_speed())
402 throw InvalidState("Must be stopped before unplacing");
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=cur_blocks_end; i!=blocks.end(); ++i)
424 if(i->block()==&block)
428 release_blocks(i, blocks.end());
431 else if((*i)->get_sensor_id())
438 void Train::free_noncritical_blocks()
443 if(controller->get_speed()==0)
445 release_blocks(cur_blocks_end, blocks.end());
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 = blocks.begin();
457 while(block!=blocks.end() && !(*block)->has_track(*track))
460 if(block==cur_blocks_end)
464 float dist = veh.get_offset();
468 dist = track->get_type().get_path_length(track->get_active_path())-dist;
469 dist -= veh.get_type().get_length()/2;
474 track = track.next();
476 if(!(*block)->has_track(*track))
479 if(block==cur_blocks_end)
481 if(block==blocks.end())
484 if(dist>min_dist && nsens>0)
486 release_blocks(block, blocks.end());
490 if(in_rsv && (*block)->get_sensor_id())
494 dist += track->get_type().get_path_length(track->get_active_path());
498 int Train::get_entry_to_block(Block &block) const
500 for(BlockList::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
501 if(i->block()==&block)
506 float Train::get_reserved_distance() const
508 return get_reserved_distance_until(0, false);
511 void Train::tick(const Time::TimeStamp &t, const Time::TimeDelta &dt)
513 if(!active && stop_timeout && t>=stop_timeout)
515 release_blocks(cur_blocks_end, blocks.end());
516 end_of_route = false;
517 stop_timeout = Time::TimeStamp();
520 Driver &driver = layout.get_driver();
524 controller->tick(dt);
525 float speed = controller->get_speed();
526 unsigned speed_notch = find_speed(speed);
528 if(controller->get_reverse()!=reverse)
530 reverse = controller->get_reverse();
531 driver.set_loco_reverse(address, reverse);
533 release_blocks(cur_blocks_end, blocks.end());
534 reverse_blocks(blocks);
538 if(speed_notch!=current_speed && !speed_changing && !driver.is_halted() && driver.get_power())
540 speed_changing = true;
541 driver.set_loco_speed(address, speed_notch);
546 set_status(format("Traveling %d kmh", get_travel_speed()));
548 set_status("Waiting");
556 Vehicle &vehicle = *(reverse ? vehicles.back() : vehicles.front());
557 Track *track = vehicle.get_track();
560 for(BlockList::const_iterator i=blocks.begin(); (!ok && i!=cur_blocks_end); ++i)
561 ok = (*i)->has_track(*track);
563 float d = get_real_speed(current_speed)*(dt/Time::sec);
566 SetFlag setf(advancing);
567 vehicle.advance(reverse ? -d : d);
569 else if(accurate_position)
572 if(overshoot_dist>40*layout.get_catalogue().get_scale())
574 layout.emergency(name+" has not arrived at sensor");
575 accurate_position = false;
579 else if(end_of_route && cur_blocks_end==blocks.end())
582 signal_arrived.emit();
586 if(!blocks.empty() && !blocks.front()->get_sensor_id())
588 float dist = get_reserved_distance_until(&*blocks.front(), true);
590 if(dist>10*layout.get_catalogue().get_scale())
592 blocks.front()->reserve(0);
598 void Train::save(list<DataFile::Statement> &st) const
600 st.push_back((DataFile::Statement("name"), name));
602 st.push_back((DataFile::Statement("priority"), priority));
604 for(vector<Vehicle *>::const_iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
605 if(i!=vehicles.begin())
606 st.push_back((DataFile::Statement("vehicle"), (*i)->get_type().get_article_number()));
608 for(unsigned i=0; i<=14; ++i)
609 if(real_speed[i].weight)
610 st.push_back((DataFile::Statement("real_speed"), i, real_speed[i].speed, real_speed[i].weight));
612 if(!blocks.empty() && cur_blocks_end!=blocks.begin())
614 BlockList blks(blocks.begin(), BlockList::const_iterator(cur_blocks_end));
616 reverse_blocks(blks);
618 BlockIter prev = blks.front().flip();
619 st.push_back((DataFile::Statement("block_hint"), prev->get_id()));
621 for(BlockList::const_iterator i=blks.begin(); i!=blks.end(); ++i)
622 st.push_back((DataFile::Statement("block"), (*i)->get_id()));
627 list<RouteRef>::const_iterator i = routes.begin();
628 for(; (i!=routes.end() && i->route->is_temporary()); ++i) ;
630 st.push_back((DataFile::Statement("route"), i->route->get_name()));
635 DataFile::Statement ss("timetable");
636 timetable->save(ss.sub);
641 void Train::control_changed(const Controller::Control &ctrl)
643 signal_control_changed.emit(ctrl.name, ctrl.value);
646 void Train::loco_speed_event(unsigned addr, unsigned speed, bool)
650 current_speed = speed;
651 speed_changing = false;
656 void Train::loco_func_event(unsigned addr, unsigned func, bool state)
658 if(addr==address || (addr==address+1 && loco_type.get_max_function()>4))
663 functions |= 1<<func;
665 functions &= ~(1<<func);
667 signal_function_changed.emit(func, state);
671 void Train::sensor_event(unsigned addr, bool state)
675 // Find the first sensor block from our reserved blocks that isn't this sensor
676 BlockList::iterator end;
678 for(end=cur_blocks_end; end!=blocks.end(); ++end)
679 if((*end)->get_sensor_id())
681 if((*end)->get_sensor_id()!=addr)
696 // Compute speed and update related state
697 float travel_time_secs = (Time::now()-last_entry_time)/Time::sec;
703 RealSpeed &rs = real_speed[current_speed];
704 rs.add(travel_dist/travel_time_secs, travel_time_secs);
706 set_status(format("Traveling %d kmh", get_travel_speed()));
710 for(BlockList::iterator j=cur_blocks_end; j!=end; ++j)
712 travel_dist += (*j)->get_path_length(j->entry());
714 if((*j)->get_sensor_id()==addr && !advancing)
716 TrackIter track = j->track_iter();
719 track = track.flip();
720 vehicles.back()->place(*track, track.entry(), 0, Vehicle::BACK_AXLE);
723 vehicles.front()->place(*track, track.entry(), 0, Vehicle::FRONT_AXLE);
726 last_entry_time = Time::now();
728 accurate_position = true;
731 // Check if we've reached the next route
734 const set<Track *> &rtracks = (++routes.begin())->route->get_tracks();
735 for(BlockList::iterator j=cur_blocks_end; j!=end; ++j)
736 if(rtracks.count((*j)->get_endpoints()[j->entry()].track))
740 signal_route_changed.emit(routes.front().route);
745 // Move blocks up to the next sensor to our current blocks
746 cur_blocks_end = end;
748 // Try to get more blocks if we're moving
753 layout.emergency("Sensor for "+name+" triggered out of order");
757 const Vehicle &veh = *(reverse ? vehicles.front() : vehicles.back());
759 // Find the first sensor in our current blocks that's still active
760 BlockList::iterator end = blocks.begin();
761 for(BlockList::iterator i=blocks.begin(); i!=cur_blocks_end; ++i)
763 if((*i)->has_track(*veh.get_track()))
765 if((*i)->get_sensor_id())
767 if(layout.get_driver().get_sensor((*i)->get_sensor_id()))
777 if(end!=blocks.begin() && end!=cur_blocks_end)
778 // Free blocks up to the last inactive sensor
779 release_blocks(blocks.begin(), end);
783 void Train::turnout_path_changed(Track &track)
785 for(list<BlockIter>::iterator i=blocks.begin(); i!=blocks.end(); ++i)
786 if((*i)->get_turnout_id()==track.get_turnout_id())
789 check_turnout_paths(false);
790 else if(i==clear_blocks_end)
795 void Train::halt_event(bool h)
798 accurate_position = false;
801 void Train::block_reserved(const Block &block, const Train *train)
803 if(&block==pending_block && !train && !reserving)
807 unsigned Train::reserve_more()
809 if(!active || blocks.empty())
812 BlockIter start = blocks.back();
816 // See how many sensor blocks and how much track we already have
819 for(BlockList::const_iterator i=cur_blocks_end; i!=blocks.end(); ++i)
821 if((*i)->get_sensor_id())
824 dist += (*i)->get_path_length(i->entry());
830 list<RouteRef>::iterator cur_route = routes.begin();
831 advance_route(cur_route, *start.track_iter());
833 float approach_margin = 50*layout.get_catalogue().get_scale();
834 float min_dist = controller->get_braking_distance()*1.3+approach_margin*2;
836 BlockIter block = start;
837 list<BlockIter>::iterator good_end = blocks.end();
838 Track *divert_track = 0;
839 bool try_divert = false;
840 unsigned good_sens = nsens;
841 float good_dist = dist;
842 Train *blocking_train = 0;
843 BlockList contested_blocks;
845 SetFlag setf(reserving);
847 while(good_sens<3 || good_dist<min_dist || !contested_blocks.empty())
849 BlockIter last = block;
850 block = block.next(cur_route!=routes.end() ? cur_route->route : 0);
854 TrackIter track = block.track_iter();
856 if(cur_route!=routes.end())
858 if(!advance_route(cur_route, *track))
860 // Keep the blocks if we arrived at the end of the route
863 good_end = blocks.end();
871 else if(!routes.empty() && routes.front().route->has_track(*track))
872 cur_route = routes.begin();
874 if(block->get_endpoints().size()<2)
878 good_end = blocks.end();
887 if(block->get_train()!=blocking_train)
889 if(blocking_train->free_block(*contested_blocks.back()))
891 // Roll back and start actually reserving the blocks
892 block = blocks.back();
893 cur_route = routes.begin();
894 advance_route(cur_route, *block.track_iter().track());
895 if(blocking_train->get_priority()==priority)
896 blocking_train->yield_to(*this);
902 yield_to(*blocking_train);
903 pending_block = contested_blocks.front().block();
904 try_divert = divert_track;
910 contested_blocks.push_back(block);
915 bool reserved = block->reserve(this);
918 /* We've found another train. If it wants to exit the block from the
919 same endpoint we're trying to enter from or the other way around,
920 treat it as coming towards us. Otherwise treat it as going in the
922 Train *other_train = block->get_train();
923 int other_entry = other_train->get_entry_to_block(*block);
925 throw LogicError("Block reservation inconsistency");
927 unsigned exit = block.reverse().entry();
928 unsigned other_exit = BlockIter(block.block(), other_entry).reverse().entry();
929 bool entry_conflict = (block.entry()==other_exit);
930 bool exit_conflict = (exit==static_cast<unsigned>(other_entry));
931 if(!entry_conflict && !last->get_turnout_id())
933 /* The other train is not coming to the blocks we're holding, so we
935 good_end = blocks.end();
940 int other_prio = other_train->get_priority();
942 if(!entry_conflict && !exit_conflict && other_prio<priority)
944 /* Ask a lesser priority train going to the same direction to free
946 if(other_train->free_block(*block))
947 reserved = block->reserve(this);
949 else if(other_train!=yielding_to && (other_prio<priority || (other_prio==priority && entry_conflict)))
951 /* A lesser priority train is coming at us, we must ask it to free
952 enough blocks to get clear of it to avoid a potential deadlock */
953 blocking_train = other_train;
954 contested_blocks.clear();
955 contested_blocks.push_back(block);
958 else if(divert_track && (entry_conflict || exit_conflict))
959 // We are blocked, but there's a diversion possibility
964 pending_block = &*block;
969 if(block->get_turnout_id())
971 const TrackType::Endpoint &track_ep = track->get_type().get_endpoints()[track.entry()];
972 bool multiple_paths = (track_ep.paths&(track_ep.paths-1));
974 if(multiple_paths || !last->get_turnout_id())
976 /* We can keep the blocks reserved so far if we are facing the
977 points or if there was no turnout immediately before this one.
978 With multiple successive turnouts (as is common in crossovers) it's
979 best to hold at one we can divert from. */
980 good_end = blocks.end();
985 if(multiple_paths && cur_route!=routes.end() && cur_route->diversion!=block->get_turnout_id())
986 /* There's multiple paths to be taken and we are on a route - take
987 note of the diversion possibility */
988 divert_track = &*track;
991 if(!contested_blocks.empty() && contested_blocks.front()==block)
992 contested_blocks.pop_front();
994 blocks.push_back(block);
996 if(cur_blocks_end==blocks.end())
998 if(clear_blocks_end==blocks.end())
1000 if(good_end==blocks.end())
1003 if(block->get_sensor_id())
1006 dist += block->get_path_length(block.entry());
1009 // Unreserve blocks that were not good
1010 release_blocks(good_end, blocks.end());
1012 if(blocks.back()!=start)
1013 // We got some new blocks, so no longer need to yield
1016 check_turnout_paths(true);
1018 // Make any sensorless blocks at the beginning immediately current
1019 while(cur_blocks_end!=blocks.end() && !(*cur_blocks_end)->get_sensor_id())
1022 if(try_divert && divert(*divert_track))
1023 return reserve_more();
1028 void Train::check_turnout_paths(bool set)
1030 if(clear_blocks_end==blocks.end())
1033 list<RouteRef>::iterator route = routes.begin();
1035 for(list<BlockIter>::iterator i=clear_blocks_end; i!=blocks.end(); ++i)
1037 advance_route(route, *i->track_iter());
1039 if((*i)->get_turnout_id())
1041 TrackIter track = i->track_iter();
1042 const TrackType::Endpoint &track_ep = track->get_type().get_endpoints()[track.entry()];
1045 for(list<RouteRef>::iterator j=route; (path<0 && j!=routes.end()); ++j)
1046 path = j->route->get_turnout((*i)->get_turnout_id());
1048 path = track->get_active_path();
1049 if(!(track_ep.paths&(1<<path)))
1051 list<BlockIter>::iterator j = i;
1052 if(++j!=blocks.end())
1054 TrackIter rev = j->track_iter().flip();
1055 unsigned mask = rev->get_type().get_endpoints()[rev.entry()].paths&track_ep.paths;
1056 for(path=0; mask>1; mask>>=1, ++path) ;
1062 if(path!=static_cast<int>(track->get_active_path()))
1065 track->set_active_path(path);
1071 if(i==clear_blocks_end)
1076 float Train::get_reserved_distance_until(const Block *until_block, bool back) const
1081 Vehicle &veh = *(reverse!=back ? vehicles.back() : vehicles.front());
1082 const VehicleType &vtype = veh.get_type();
1084 TrackIter track(veh.get_track(), veh.get_entry());
1085 if(!track) // XXX Probably unnecessary
1088 BlockList::const_iterator block = blocks.begin();
1089 while(block!=clear_blocks_end && !(*block)->has_track(*track))
1091 if(block==clear_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==blocks.begin())
1118 if(block==clear_blocks_end)
1122 if(&**block==until_block)
1126 result += track->get_type().get_path_length(track->get_active_path());
1132 float Train::get_real_speed(unsigned i) const
1134 if(real_speed[i].weight)
1135 return real_speed[i].speed;
1139 for(low=i; low>0; --low)
1140 if(real_speed[low].weight)
1142 for(high=i; high<14; ++high)
1143 if(real_speed[high].weight)
1146 if(real_speed[high].weight)
1148 if(real_speed[low].weight)
1150 float f = float(i-low)/(high-low);
1151 return real_speed[low].speed*(1-f)+real_speed[high].speed*f;
1154 return real_speed[high].speed*float(i)/high;
1156 else if(real_speed[low].weight)
1157 return real_speed[low].speed*float(i)/low;
1162 unsigned Train::find_speed(float real) const
1164 if(real<=real_speed[0].speed)
1170 for(unsigned i=0; (!high && i<=14); ++i)
1171 if(real_speed[i].weight)
1174 if(real_speed[i].speed<real)
1188 return min(min(static_cast<unsigned>(low*real/real_speed[low].speed), 14U), last+3);
1191 float f = (real-real_speed[low].speed)/(real_speed[high].speed-real_speed[low].speed);
1192 return static_cast<unsigned>(low*(1-f)+high*f+0.5);
1195 float Train::get_travel_speed() const
1197 float speed = get_real_speed(current_speed);
1198 float scale = layout.get_catalogue().get_scale();
1199 return static_cast<int>(round(speed/scale*3.6/5))*5;
1202 void Train::set_status(const string &s)
1205 signal_status_changed.emit(s);
1208 void Train::release_blocks()
1210 release_blocks(blocks.begin(), blocks.end());
1213 void Train::release_blocks(BlockList::iterator begin, BlockList::iterator end)
1217 if(begin==cur_blocks_end)
1218 cur_blocks_end = end;
1219 if(begin==clear_blocks_end)
1220 clear_blocks_end = end;
1222 Block &block = **begin;
1223 blocks.erase(begin++);
1228 void Train::reverse_blocks(BlockList &blks) const
1231 for(BlockList::iterator i=blks.begin(); i!=blks.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=blocks.begin(); i!=blocks.end(); ++i)
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))
1268 lead->add_tracks(tracks);
1273 bool Train::is_valid_diversion(const Route &diversion, const TrackIter &from)
1275 float diversion_len = 0;
1276 TrackLoopIter track1 = from;
1277 while(diversion.has_track(*track1))
1279 unsigned path = diversion.get_path(*track1);
1280 diversion_len += track1->get_type().get_path_length(path);
1282 track1 = track1.next(path);
1288 list<RouteRef>::iterator route = routes.begin();
1289 if(!advance_route(route, *from))
1292 float route_len = 0;
1293 TrackLoopIter track2 = from;
1296 unsigned path = route->route->get_path(*track2);
1297 route_len += track2->get_type().get_path_length(path);
1299 bool ok = (track2!=from && diversion.has_track(*track2));
1301 track2 = track2.next(path);
1309 if(!advance_route(route, *track2))
1313 // Must end up at the same place through both routes
1317 return diversion_len<route_len*1.2;
1321 Train::RouteRef::RouteRef(const Route *r, unsigned d):
1327 Train::RealSpeed::RealSpeed():
1332 void Train::RealSpeed::add(float s, float w)
1334 speed = (speed*weight+s*w)/(weight+w);
1335 weight = min(weight+w, 300.0f);
1339 Train::Loader::Loader(Train &t):
1340 DataFile::BasicLoader<Train>(t),
1344 add("block", &Loader::block);
1345 add("block_hint", &Loader::block_hint);
1346 add("name", &Loader::name);
1347 add("priority", &Train::priority);
1348 add("real_speed", &Loader::real_speed);
1349 add("route", &Loader::route);
1350 add("timetable", &Loader::timetable);
1351 add("vehicle", &Loader::vehicle);
1354 void Train::Loader::finish()
1356 if(!obj.blocks.empty())
1358 TrackIter track = obj.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.blocks.push_back(BlockIter(blk, entry));
1391 if(blk->get_sensor_id())
1392 obj.layout.get_driver().set_sensor(blk->get_sensor_id(), true);
1397 void Train::Loader::block_hint(unsigned id)
1401 prev_block = &obj.layout.get_block(id);
1403 catch(const KeyError &)
1405 blocks_valid = false;
1409 void Train::Loader::name(const string &n)
1414 void Train::Loader::real_speed(unsigned i, float speed, float weight)
1416 obj.real_speed[i].speed = speed;
1417 obj.real_speed[i].weight = weight;
1420 void Train::Loader::route(const string &n)
1422 obj.set_route(&obj.layout.get_route(n));
1425 void Train::Loader::timetable()
1428 throw InvalidState("A timetable has already been loaded");
1430 obj.timetable = new Timetable(obj);
1431 load_sub(*obj.timetable);
1434 void Train::Loader::vehicle(ArticleNumber art_nr)
1436 const VehicleType &vtype = obj.layout.get_catalogue().get_vehicle(art_nr);
1437 Vehicle *veh = new Vehicle(obj.layout, vtype);
1438 obj.vehicles.back()->attach_back(*veh);
1439 obj.vehicles.push_back(veh);
1442 } // namespace Marklin