3 This file is part of R²C²
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"
35 SetFlag(bool &f): flag(f) { flag = true; }
36 ~SetFlag() { flag = false; }
44 Train::Train(Layout &l, const VehicleType &t, unsigned a, const string &p):
52 cur_blocks_end(blocks.end()),
53 clear_blocks_end(blocks.end()),
57 controller(new AIControl(*this, new SimpleController)),
60 current_speed_step(0),
61 speed_changing(false),
68 real_speed(layout.get_driver().get_protocol_speed_steps(protocol)+1),
69 accurate_position(false),
72 if(!loco_type.is_locomotive())
73 throw InvalidParameterValue("Initial vehicle must be a locomotive");
75 vehicles.push_back(new Vehicle(layout, loco_type));
77 layout.add_train(*this);
79 layout.get_driver().add_loco(address, protocol, loco_type);
80 layout.get_driver().signal_loco_speed.connect(sigc::mem_fun(this, &Train::loco_speed_event));
81 layout.get_driver().signal_loco_function.connect(sigc::mem_fun(this, &Train::loco_func_event));
83 layout.signal_block_reserved.connect(sigc::mem_fun(this, &Train::block_reserved));
84 layout.get_driver().signal_sensor.connect(sigc::mem_fun(this, &Train::sensor_event));
86 layout.get_driver().signal_halt.connect(sigc::mem_fun(this, &Train::halt_event));
88 const set<Track *> &tracks = layout.get_tracks();
89 for(set<Track *>::const_iterator i=tracks.begin(); i!=tracks.end(); ++i)
90 if((*i)->get_turnout_id())
91 (*i)->signal_path_changed.connect(sigc::hide(sigc::bind(sigc::mem_fun(this, &Train::turnout_path_changed), sigc::ref(**i))));
93 controller->signal_control_changed.connect(sigc::mem_fun(this, &Train::control_changed));
100 for(vector<Vehicle *>::iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
102 layout.remove_train(*this);
105 void Train::set_name(const string &n)
109 signal_name_changed.emit(name);
112 void Train::set_priority(int p)
117 void Train::yield_to(const Train &t)
122 void Train::add_vehicle(const VehicleType &vt)
124 Vehicle *veh = new Vehicle(layout, vt);
125 vehicles.back()->attach_back(*veh);
126 vehicles.push_back(veh);
129 void Train::remove_vehicle(unsigned i)
131 if(i>=vehicles.size())
132 throw InvalidParameterValue("Vehicle index out of range");
134 throw InvalidParameterValue("Can't remove the locomotive");
136 vehicles.erase(vehicles.begin()+i);
137 if(i<vehicles.size())
138 vehicles[i-1]->attach_back(*vehicles[i]);
141 unsigned Train::get_n_vehicles() const
143 return vehicles.size();
146 Vehicle &Train::get_vehicle(unsigned i)
148 if(i>=vehicles.size())
149 throw InvalidParameterValue("Vehicle index out of range");
153 const Vehicle &Train::get_vehicle(unsigned i) const
155 if(i>=vehicles.size())
156 throw InvalidParameterValue("Vehicle index out of range");
160 void Train::set_control(const string &n, float v)
162 controller->set_control(n, v);
165 void Train::set_active(bool a)
169 if(!a && controller->get_speed())
170 throw InvalidState("Can't deactivate while moving");
175 stop_timeout = Time::TimeStamp();
180 stop_timeout = Time::now()+2*Time::sec;
181 set_status("Stopped");
185 void Train::set_function(unsigned func, bool state)
187 if(!loco_type.get_functions().count(func))
188 throw InvalidParameterValue("Invalid function");
189 layout.get_driver().set_loco_function(address, func, 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::go_to(const Zone &to)
271 for(BlockList::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
272 tracks.insert((*i)->get_tracks().begin(), (*i)->get_tracks().end());
274 const Zone::TrackSet &ztracks = to.get_tracks();
275 unsigned union_size = 0;
276 for(Zone::TrackSet::const_iterator i=ztracks.begin(); i!=ztracks.end(); ++i)
277 union_size += tracks.count(*i);
279 if(union_size==tracks.size() || union_size==ztracks.size())
281 signal_arrived.emit();
285 free_noncritical_blocks();
287 TrackIter next = blocks.back().next().track_iter();
289 Route *route = Route::find(next, to);
292 create_lead_route(route, route);
293 route->add_tracks(ztracks);
294 return set_route(route);
297 bool Train::divert(Track &from)
299 if(!from.get_turnout_id())
300 throw InvalidParameterValue("Can't divert from a non-turnout");
306 list<RouteRef>::iterator route = routes.begin();
308 // Follow our routes to find out where we're entering the turnout
309 for(TrackLoopIter track = blocks.front().track_iter();;)
311 if(!advance_route(route, *track))
316 Block &block = track->get_block();
317 if(block.get_train()==this && !free_block(block))
320 int route_path = route->route->get_turnout(from.get_turnout_id());
322 // Check that more than one path is available
323 unsigned ep_paths = track.endpoint().paths;
324 if(!(ep_paths&(ep_paths-1)))
327 // Choose some other path
328 for(int i=0; ep_paths>>i; ++i)
329 if((ep_paths&(1<<i)) && i!=route_path)
335 entry = track.entry();
339 track = track.next(route->route->get_path(*track));
341 if(!track || track.looped())
345 TrackIter track = TrackIter(&from, entry).next(path);
350 for(list<RouteRef>::iterator i=routes.begin(); i!=routes.end(); ++i)
351 tracks.insert(i->route->get_tracks().begin(), i->route->get_tracks().end());
352 RefPtr<Route> diversion = Route::find(track, tracks);
356 diversion->set_name("Diversion");
357 diversion->add_track(from);
358 diversion->set_turnout(from.get_turnout_id(), path);
360 if(!is_valid_diversion(*diversion, TrackIter(&from, entry)))
363 // Follow the diversion route until we get back to the original route
364 list<RouteRef>::iterator end = routes.end();
367 for(list<RouteRef>::iterator i=route; (end==routes.end() && i!=routes.end()); ++i)
368 if(i->route->has_track(*track))
371 if(end!=routes.end())
373 else if(!diversion->has_track(*track))
374 throw LogicError("Pathfinder returned a bad route");
376 track = track.next(diversion->get_path(*track));
380 // We are rejoining the same route we diverted from, duplicate it
381 routes.insert(end, *route);
385 routes.erase(route, end);
387 routes.insert(end, RouteRef(diversion.release(), from.get_turnout_id()));
392 const Route *Train::get_route() const
396 return routes.front().route;
399 void Train::place(Block &block, unsigned entry)
401 if(controller->get_speed())
402 throw InvalidState("Must be stopped before placing");
407 accurate_position = false;
409 if(!block.reserve(this))
411 set_status("Unplaced");
415 blocks.push_back(BlockIter(&block, entry));
418 TrackIter track = BlockIter(&block, entry).reverse().track_iter();
419 vehicles.front()->place(*track, track.entry(), 0, Vehicle::FRONT_BUFFER);
423 const Block::Endpoint &bep = block.get_endpoint(entry);
424 vehicles.back()->place(*bep.track, bep.track_ep, 0, Vehicle::BACK_BUFFER);
428 void Train::unplace()
430 if(controller->get_speed())
431 throw InvalidState("Must be stopped before unplacing");
436 accurate_position = false;
438 for(vector<Vehicle *>::iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
441 set_status("Unplaced");
444 bool Train::free_block(Block &block)
446 float margin = 10*layout.get_catalogue().get_scale();
447 if(get_reserved_distance_until(&block, false)<controller->get_braking_distance()*1.3+margin)
451 for(BlockList::iterator i=cur_blocks_end; i!=blocks.end(); ++i)
453 if(i->block()==&block)
457 release_blocks(i, blocks.end());
460 else if((*i)->get_sensor_id())
467 void Train::free_noncritical_blocks()
472 if(controller->get_speed()==0)
474 release_blocks(cur_blocks_end, blocks.end());
478 float margin = 10*layout.get_catalogue().get_scale();
479 float min_dist = controller->get_braking_distance()*1.3+margin;
481 Vehicle &veh = *(reverse ? vehicles.back() : vehicles.front());
483 TrackIter track(veh.get_track(), veh.get_entry());
484 BlockList::iterator block = blocks.begin();
486 while(block!=blocks.end() && !(*block)->has_track(*track))
489 if(block==cur_blocks_end)
493 float dist = veh.get_offset();
497 dist = track->get_type().get_path_length(track->get_active_path())-dist;
498 dist -= veh.get_type().get_length()/2;
503 track = track.next();
505 if(!(*block)->has_track(*track))
508 if(block==cur_blocks_end)
510 if(block==blocks.end())
513 if(dist>min_dist && nsens>0)
515 release_blocks(block, blocks.end());
519 if(in_rsv && (*block)->get_sensor_id())
523 dist += track->get_type().get_path_length(track->get_active_path());
527 int Train::get_entry_to_block(Block &block) const
529 for(BlockList::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
530 if(i->block()==&block)
535 float Train::get_reserved_distance() const
537 return get_reserved_distance_until(0, false);
540 void Train::tick(const Time::TimeStamp &t, const Time::TimeDelta &dt)
542 if(!active && stop_timeout && t>=stop_timeout)
544 release_blocks(cur_blocks_end, blocks.end());
545 stop_timeout = Time::TimeStamp();
548 Driver &driver = layout.get_driver();
552 controller->tick(dt);
553 float speed = controller->get_speed();
554 unsigned speed_step = find_speed_step(speed);
556 if(controller->get_reverse()!=reverse)
558 reverse = controller->get_reverse();
559 driver.set_loco_reverse(address, reverse);
561 release_blocks(cur_blocks_end, blocks.end());
562 reverse_blocks(blocks);
566 if(speed_step!=current_speed_step && !speed_changing && !driver.is_halted() && driver.get_power())
568 speed_changing = true;
569 driver.set_loco_speed(address, speed_step);
574 set_status(format("Traveling %d kmh", get_travel_speed()));
576 set_status("Waiting");
584 Vehicle &vehicle = *(reverse ? vehicles.back() : vehicles.front());
585 Track *track = vehicle.get_track();
588 for(BlockList::const_iterator i=blocks.begin(); (!ok && i!=cur_blocks_end); ++i)
589 ok = (*i)->has_track(*track);
592 if(real_speed.size()>1)
593 d = get_real_speed(current_speed_step)*(dt/Time::sec);
595 d = speed*(dt/Time::sec);
598 SetFlag setf(advancing);
599 vehicle.advance(reverse ? -d : d);
601 else if(accurate_position)
604 if(overshoot_dist>40*layout.get_catalogue().get_scale())
606 layout.emergency(name+" has not arrived at sensor");
607 accurate_position = false;
611 else if(end_of_route && cur_blocks_end==blocks.end())
614 signal_arrived.emit();
618 if(!blocks.empty() && !blocks.front()->get_sensor_id())
620 float dist = get_reserved_distance_until(&*blocks.front(), true);
622 if(dist>10*layout.get_catalogue().get_scale())
624 blocks.front()->reserve(0);
630 void Train::save(list<DataFile::Statement> &st) const
632 st.push_back((DataFile::Statement("name"), name));
634 st.push_back((DataFile::Statement("priority"), priority));
636 for(vector<Vehicle *>::const_iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
637 if(i!=vehicles.begin())
638 st.push_back((DataFile::Statement("vehicle"), (*i)->get_type().get_article_number()));
640 for(unsigned i=0; i<real_speed.size(); ++i)
641 if(real_speed[i].weight)
642 st.push_back((DataFile::Statement("real_speed"), i, real_speed[i].speed, real_speed[i].weight));
644 if(!blocks.empty() && cur_blocks_end!=blocks.begin())
646 BlockList blks(blocks.begin(), BlockList::const_iterator(cur_blocks_end));
648 reverse_blocks(blks);
650 BlockIter prev = blks.front().flip();
651 st.push_back((DataFile::Statement("block_hint"), prev->get_id()));
653 for(BlockList::const_iterator i=blks.begin(); i!=blks.end(); ++i)
654 st.push_back((DataFile::Statement("block"), (*i)->get_id()));
659 list<RouteRef>::const_iterator i = routes.begin();
660 for(; (i!=routes.end() && i->route->is_temporary()); ++i) ;
662 st.push_back((DataFile::Statement("route"), i->route->get_name()));
667 DataFile::Statement ss("timetable");
668 timetable->save(ss.sub);
673 void Train::control_changed(const Controller::Control &ctrl)
675 signal_control_changed.emit(ctrl.name, ctrl.value);
678 void Train::loco_speed_event(unsigned addr, unsigned speed, bool rev)
682 current_speed_step = speed;
684 layout.get_driver().set_loco_reverse(address, reverse);
685 speed_changing = false;
690 void Train::loco_func_event(unsigned addr, unsigned func, bool state)
695 functions |= 1<<func;
697 functions &= ~(1<<func);
699 signal_function_changed.emit(func, state);
703 void Train::sensor_event(unsigned addr, bool state)
707 // Find the first sensor block from our reserved blocks that isn't this sensor
708 BlockList::iterator end;
710 for(end=cur_blocks_end; end!=blocks.end(); ++end)
711 if((*end)->get_sensor_id())
713 if((*end)->get_sensor_id()!=addr)
728 // Compute speed and update related state
729 float travel_time_secs = (Time::now()-last_entry_time)/Time::sec;
733 if(current_speed_step>0)
735 RealSpeed &rs = real_speed[current_speed_step];
736 rs.add(travel_dist/travel_time_secs, travel_time_secs);
738 set_status(format("Traveling %d kmh", get_travel_speed()));
742 for(BlockList::iterator j=cur_blocks_end; j!=end; ++j)
744 travel_dist += (*j)->get_path_length(j->entry());
746 if((*j)->get_sensor_id()==addr && !advancing)
748 TrackIter track = j->track_iter();
751 track = track.flip();
752 vehicles.back()->place(*track, track.entry(), 0, Vehicle::BACK_AXLE);
755 vehicles.front()->place(*track, track.entry(), 0, Vehicle::FRONT_AXLE);
758 last_entry_time = Time::now();
760 accurate_position = true;
763 // Check if we've reached the next route
766 const Route &route = *(++routes.begin())->route;
767 for(BlockList::iterator j=cur_blocks_end; j!=end; ++j)
768 if(route.has_track(*j->track_iter()))
772 signal_route_changed.emit(routes.front().route);
777 // Move blocks up to the next sensor to our current blocks
778 cur_blocks_end = end;
780 // Try to get more blocks if we're moving
785 layout.emergency("Sensor for "+name+" triggered out of order");
789 const Vehicle &veh = *(reverse ? vehicles.front() : vehicles.back());
791 // Find the first sensor in our current blocks that's still active
792 BlockList::iterator end = blocks.begin();
793 for(BlockList::iterator i=blocks.begin(); i!=cur_blocks_end; ++i)
795 if((*i)->has_track(*veh.get_track()))
797 if((*i)->get_sensor_id())
799 if(layout.get_driver().get_sensor((*i)->get_sensor_id()))
809 if(end!=blocks.begin() && end!=cur_blocks_end)
810 // Free blocks up to the last inactive sensor
811 release_blocks(blocks.begin(), end);
815 void Train::turnout_path_changed(Track &track)
817 for(list<BlockIter>::iterator i=blocks.begin(); i!=blocks.end(); ++i)
818 if((*i)->get_turnout_id()==track.get_turnout_id() && !reserving)
819 check_turnout_paths(false);
822 void Train::halt_event(bool h)
825 accurate_position = false;
828 void Train::block_reserved(const Block &block, const Train *train)
830 if(&block==pending_block && !train && !reserving)
834 void Train::reserve_more()
836 if(!active || blocks.empty() || end_of_route)
839 BlockIter start = blocks.back();
844 // See how many sensor blocks and how much track we already have
847 for(BlockList::const_iterator i=cur_blocks_end; i!=blocks.end(); ++i)
849 if((*i)->get_sensor_id())
852 dist += (*i)->get_path_length(i->entry());
855 list<RouteRef>::iterator cur_route = routes.begin();
856 advance_route(cur_route, *start.track_iter());
858 float approach_margin = 50*layout.get_catalogue().get_scale();
859 float min_dist = controller->get_braking_distance()*1.3+approach_margin*2;
861 BlockIter block = start;
862 list<BlockIter>::iterator good_end = blocks.end();
863 Track *divert_track = 0;
864 bool try_divert = false;
865 Train *blocking_train = 0;
866 BlockList contested_blocks;
868 SetFlag setf(reserving);
872 BlockIter last = block;
873 block = block.next(cur_route!=routes.end() ? cur_route->route : 0);
874 if(!block || block->get_endpoints().size()<2)
877 good_end = blocks.end();
881 TrackIter track = block.track_iter();
883 if(cur_route!=routes.end())
885 if(!advance_route(cur_route, *track))
887 // Keep the blocks if we arrived at the end of the route
890 good_end = blocks.end();
897 if(block->get_turnout_id() && !last->get_turnout_id())
899 /* We can keep the blocks if we arrive at a turnout from a non-turnout
900 block. Having a turnout block as our last reserved block is not good
901 as it would limit our diversion possibilities for little benefit. */
902 good_end = blocks.end();
903 if(nsens>=3 && dist>=min_dist)
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 = 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
957 good_end = blocks.end();
959 if(static_cast<unsigned>(other_entry)==block.entry())
960 preceding_train = other_train;
963 int other_prio = other_train->get_priority();
965 if(!entry_conflict && !exit_conflict && other_prio<priority)
967 /* Ask a lesser priority train going to the same direction to free
969 if(other_train->free_block(*block))
970 reserved = block->reserve(this);
972 else if(other_train!=yielding_to && (other_prio<priority || (other_prio==priority && entry_conflict)))
974 /* A lesser priority train is coming at us, we must ask it to free
975 enough blocks to get clear of it to avoid a potential deadlock */
976 blocking_train = other_train;
977 contested_blocks.clear();
978 contested_blocks.push_back(block);
981 else if(divert_track && (entry_conflict || exit_conflict))
982 // We are blocked, but there's a diversion possibility
987 pending_block = &*block;
992 if(block->get_turnout_id())
994 const TrackType::Endpoint &track_ep = track.endpoint();
995 bool multiple_paths = (track_ep.paths&(track_ep.paths-1));
997 if(multiple_paths && cur_route!=routes.end() && cur_route->diversion!=block->get_turnout_id())
998 /* There's multiple paths to be taken and we are on a route - take
999 note of the diversion possibility */
1000 divert_track = &*track;
1003 if(!contested_blocks.empty() && contested_blocks.front()==block)
1004 contested_blocks.pop_front();
1006 blocks.push_back(block);
1008 if(cur_blocks_end==blocks.end())
1010 if(clear_blocks_end==blocks.end())
1012 if(good_end==blocks.end())
1015 if(block->get_sensor_id())
1018 dist += block->get_path_length(block.entry());
1021 // Unreserve blocks that were not good
1022 release_blocks(good_end, blocks.end());
1024 if(blocks.back()!=start)
1025 // We got some new blocks, so no longer need to yield
1028 check_turnout_paths(true);
1030 // Make any sensorless blocks at the beginning immediately current
1031 while(cur_blocks_end!=clear_blocks_end && !(*cur_blocks_end)->get_sensor_id())
1034 if(try_divert && divert(*divert_track))
1038 void Train::check_turnout_paths(bool set)
1040 if(clear_blocks_end==blocks.end())
1043 for(list<BlockIter>::iterator i=clear_blocks_end; i!=blocks.end(); ++i)
1045 if((*i)->get_turnout_id())
1047 TrackIter track = i->track_iter();
1048 const TrackType::Endpoint &track_ep = track.endpoint();
1051 list<BlockIter>::iterator j = i;
1052 if(++j!=blocks.end())
1054 TrackIter rev = j->track_iter().flip();
1055 unsigned mask = rev.endpoint().paths&track_ep.paths;
1056 for(path=0; mask>1; mask>>=1, ++path) ;
1061 if(path!=track->get_active_path())
1064 track->set_active_path(path);
1066 /* Check again, in case the driver was able to service the request
1068 if(!set || path!=track->get_active_path())
1073 if(i==clear_blocks_end)
1078 float Train::get_reserved_distance_until(const Block *until_block, bool back) const
1083 Vehicle &veh = *(reverse!=back ? vehicles.back() : vehicles.front());
1084 const VehicleType &vtype = veh.get_type();
1086 TrackIter track(veh.get_track(), veh.get_entry());
1087 if(!track) // XXX Probably unnecessary
1090 BlockList::const_iterator block = blocks.begin();
1091 while(block!=clear_blocks_end && !(*block)->has_track(*track))
1093 if(block==clear_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==blocks.begin())
1120 if(block==clear_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
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+1<real_speed.size(); ++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_step(float real) const
1168 if(real_speed.size()<=1)
1170 if(real<=real_speed[1].speed*0.5)
1176 for(unsigned i=0; (!high && i<real_speed.size()); ++i)
1177 if(real_speed[i].weight)
1180 if(real_speed[i].speed<real)
1187 unsigned limit = real_speed.size()/5;
1195 return min(min(static_cast<unsigned>(low*real/real_speed[low].speed), real_speed.size()-1), last+limit);
1198 float f = (real-real_speed[low].speed)/(real_speed[high].speed-real_speed[low].speed);
1199 return static_cast<unsigned>(low*(1-f)+high*f+0.5);
1202 float Train::get_travel_speed() const
1204 float speed = get_real_speed(current_speed_step);
1205 float scale = layout.get_catalogue().get_scale();
1206 return static_cast<int>(round(speed/scale*3.6/5))*5;
1209 void Train::set_status(const string &s)
1212 signal_status_changed.emit(s);
1215 void Train::release_blocks()
1217 release_blocks(blocks.begin(), blocks.end());
1220 void Train::release_blocks(BlockList::iterator begin, BlockList::iterator end)
1224 if(begin==cur_blocks_end)
1225 cur_blocks_end = end;
1226 if(begin==clear_blocks_end)
1227 clear_blocks_end = end;
1229 Block &block = **begin;
1230 blocks.erase(begin++);
1233 if(begin==blocks.end())
1234 end_of_route = false;
1238 void Train::reverse_blocks(BlockList &blks) const
1241 for(BlockList::iterator i=blks.begin(); i!=blks.end(); ++i)
1245 bool Train::advance_route(list<RouteRef>::iterator &iter, Track &track)
1247 while(iter!=routes.end() && !iter->route->has_track(track))
1249 if(iter==routes.end())
1252 list<RouteRef>::iterator next = iter;
1254 if(next!=routes.end() && next->diversion && next->route->has_track(track))
1260 Route *Train::create_lead_route(Route *lead, const Route *target)
1264 lead = new Route(layout);
1265 lead->set_name("Lead");
1266 lead->set_temporary(true);
1269 set<Track *> tracks;
1270 for(BlockList::iterator i=blocks.begin(); i!=blocks.end(); ++i)
1272 const set<Track *> &btracks = (*i)->get_tracks();
1273 for(set<Track *>::const_iterator j=btracks.begin(); j!=btracks.end(); ++j)
1274 if(!target || !target->has_track(**j))
1278 lead->add_tracks(tracks);
1283 bool Train::is_valid_diversion(const Route &diversion, const TrackIter &from)
1285 float diversion_len = 0;
1286 TrackLoopIter track1 = from;
1287 while(diversion.has_track(*track1))
1289 unsigned path = diversion.get_path(*track1);
1290 diversion_len += track1->get_type().get_path_length(path);
1292 track1 = track1.next(path);
1298 list<RouteRef>::iterator route = routes.begin();
1299 if(!advance_route(route, *from))
1302 float route_len = 0;
1303 TrackLoopIter track2 = from;
1306 unsigned path = route->route->get_path(*track2);
1307 route_len += track2->get_type().get_path_length(path);
1309 bool ok = (track2!=from && diversion.has_track(*track2));
1311 track2 = track2.next(path);
1319 if(!advance_route(route, *track2))
1323 // Must end up at the same place through both routes
1327 return diversion_len<route_len*1.2;
1331 Train::RouteRef::RouteRef(const Route *r, unsigned d):
1337 Train::RealSpeed::RealSpeed():
1342 void Train::RealSpeed::add(float s, float w)
1344 speed = (speed*weight+s*w)/(weight+w);
1345 weight = min(weight+w, 300.0f);
1349 Train::Loader::Loader(Train &t):
1350 DataFile::BasicLoader<Train>(t),
1354 add("block", &Loader::block);
1355 add("block_hint", &Loader::block_hint);
1356 add("name", &Loader::name);
1357 add("priority", &Train::priority);
1358 add("real_speed", &Loader::real_speed);
1359 add("route", &Loader::route);
1360 add("timetable", &Loader::timetable);
1361 add("vehicle", &Loader::vehicle);
1364 void Train::Loader::finish()
1366 if(!obj.blocks.empty())
1368 TrackIter track = obj.blocks.front().track_iter();
1369 float offset = 2*obj.layout.get_catalogue().get_scale();
1370 obj.vehicles.back()->place(*track, track.entry(), offset, Vehicle::BACK_BUFFER);
1372 obj.set_status("Stopped");
1376 void Train::Loader::block(unsigned id)
1384 blk = &obj.layout.get_block(id);
1386 catch(const KeyError &)
1388 blocks_valid = false;
1394 entry = blk->get_endpoint_by_link(*prev_block);
1399 obj.blocks.push_back(BlockIter(blk, entry));
1401 if(blk->get_sensor_id())
1402 obj.layout.get_driver().set_sensor(blk->get_sensor_id(), true);
1407 void Train::Loader::block_hint(unsigned id)
1411 prev_block = &obj.layout.get_block(id);
1413 catch(const KeyError &)
1415 blocks_valid = false;
1419 void Train::Loader::name(const string &n)
1424 void Train::Loader::real_speed(unsigned i, float speed, float weight)
1426 if(i>=obj.real_speed.size())
1428 obj.real_speed[i].speed = speed;
1429 obj.real_speed[i].weight = weight;
1432 void Train::Loader::route(const string &n)
1434 obj.set_route(&obj.layout.get_route(n));
1437 void Train::Loader::timetable()
1440 throw InvalidState("A timetable has already been loaded");
1442 obj.timetable = new Timetable(obj);
1443 load_sub(*obj.timetable);
1446 void Train::Loader::vehicle(ArticleNumber art_nr)
1448 const VehicleType &vtype = obj.layout.get_catalogue().get_vehicle(art_nr);
1449 Vehicle *veh = new Vehicle(obj.layout, vtype);
1450 obj.vehicles.back()->attach_back(*veh);
1451 obj.vehicles.push_back(veh);