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)
682 current_speed_step = speed;
683 speed_changing = false;
688 void Train::loco_func_event(unsigned addr, unsigned func, bool state)
693 functions |= 1<<func;
695 functions &= ~(1<<func);
697 signal_function_changed.emit(func, state);
701 void Train::sensor_event(unsigned addr, bool state)
705 // Find the first sensor block from our reserved blocks that isn't this sensor
706 BlockList::iterator end;
708 for(end=cur_blocks_end; end!=blocks.end(); ++end)
709 if((*end)->get_sensor_id())
711 if((*end)->get_sensor_id()!=addr)
726 // Compute speed and update related state
727 float travel_time_secs = (Time::now()-last_entry_time)/Time::sec;
731 if(current_speed_step>0)
733 RealSpeed &rs = real_speed[current_speed_step];
734 rs.add(travel_dist/travel_time_secs, travel_time_secs);
736 set_status(format("Traveling %d kmh", get_travel_speed()));
740 for(BlockList::iterator j=cur_blocks_end; j!=end; ++j)
742 travel_dist += (*j)->get_path_length(j->entry());
744 if((*j)->get_sensor_id()==addr && !advancing)
746 TrackIter track = j->track_iter();
749 track = track.flip();
750 vehicles.back()->place(*track, track.entry(), 0, Vehicle::BACK_AXLE);
753 vehicles.front()->place(*track, track.entry(), 0, Vehicle::FRONT_AXLE);
756 last_entry_time = Time::now();
758 accurate_position = true;
761 // Check if we've reached the next route
764 const Route &route = *(++routes.begin())->route;
765 for(BlockList::iterator j=cur_blocks_end; j!=end; ++j)
766 if(route.has_track(*j->track_iter()))
770 signal_route_changed.emit(routes.front().route);
775 // Move blocks up to the next sensor to our current blocks
776 cur_blocks_end = end;
778 // Try to get more blocks if we're moving
783 layout.emergency("Sensor for "+name+" triggered out of order");
787 const Vehicle &veh = *(reverse ? vehicles.front() : vehicles.back());
789 // Find the first sensor in our current blocks that's still active
790 BlockList::iterator end = blocks.begin();
791 for(BlockList::iterator i=blocks.begin(); i!=cur_blocks_end; ++i)
793 if((*i)->has_track(*veh.get_track()))
795 if((*i)->get_sensor_id())
797 if(layout.get_driver().get_sensor((*i)->get_sensor_id()))
807 if(end!=blocks.begin() && end!=cur_blocks_end)
808 // Free blocks up to the last inactive sensor
809 release_blocks(blocks.begin(), end);
813 void Train::turnout_path_changed(Track &track)
815 for(list<BlockIter>::iterator i=blocks.begin(); i!=blocks.end(); ++i)
816 if((*i)->get_turnout_id()==track.get_turnout_id() && !reserving)
817 check_turnout_paths(false);
820 void Train::halt_event(bool h)
823 accurate_position = false;
826 void Train::block_reserved(const Block &block, const Train *train)
828 if(&block==pending_block && !train && !reserving)
832 void Train::reserve_more()
834 if(!active || blocks.empty() || end_of_route)
837 BlockIter start = blocks.back();
842 // See how many sensor blocks and how much track we already have
845 for(BlockList::const_iterator i=cur_blocks_end; i!=blocks.end(); ++i)
847 if((*i)->get_sensor_id())
850 dist += (*i)->get_path_length(i->entry());
853 list<RouteRef>::iterator cur_route = routes.begin();
854 advance_route(cur_route, *start.track_iter());
856 float approach_margin = 50*layout.get_catalogue().get_scale();
857 float min_dist = controller->get_braking_distance()*1.3+approach_margin*2;
859 BlockIter block = start;
860 list<BlockIter>::iterator good_end = blocks.end();
861 Track *divert_track = 0;
862 bool try_divert = false;
863 Train *blocking_train = 0;
864 BlockList contested_blocks;
866 SetFlag setf(reserving);
870 BlockIter last = block;
871 block = block.next(cur_route!=routes.end() ? cur_route->route : 0);
872 if(!block || block->get_endpoints().size()<2)
875 good_end = blocks.end();
879 TrackIter track = block.track_iter();
881 if(cur_route!=routes.end())
883 if(!advance_route(cur_route, *track))
885 // Keep the blocks if we arrived at the end of the route
888 good_end = blocks.end();
895 if(block->get_turnout_id() && !last->get_turnout_id())
897 /* We can keep the blocks if we arrive at a turnout from a non-turnout
898 block. Having a turnout block as our last reserved block is not good
899 as it would limit our diversion possibilities for little benefit. */
900 good_end = blocks.end();
901 if(nsens>=3 && dist>=min_dist)
907 if(block->get_train()!=blocking_train)
909 if(blocking_train->free_block(*contested_blocks.back()))
911 // Roll back and start actually reserving the blocks
912 block = blocks.back();
913 cur_route = routes.begin();
914 advance_route(cur_route, *block.track_iter().track());
915 if(blocking_train->get_priority()==priority)
916 blocking_train->yield_to(*this);
922 yield_to(*blocking_train);
923 pending_block = contested_blocks.front().block();
924 try_divert = divert_track;
930 contested_blocks.push_back(block);
935 bool reserved = block->reserve(this);
938 /* We've found another train. If it wants to exit the block from the
939 same endpoint we're trying to enter from or the other way around,
940 treat it as coming towards us. Otherwise treat it as going in the
942 Train *other_train = block->get_train();
943 int other_entry = other_train->get_entry_to_block(*block);
945 throw LogicError("Block reservation inconsistency");
947 unsigned exit = block.reverse().entry();
948 unsigned other_exit = BlockIter(block.block(), other_entry).reverse().entry();
949 bool entry_conflict = (block.entry()==other_exit);
950 bool exit_conflict = (exit==static_cast<unsigned>(other_entry));
951 if(!entry_conflict && !last->get_turnout_id())
953 /* The other train is not coming to the blocks we're holding, so we
955 good_end = blocks.end();
957 if(static_cast<unsigned>(other_entry)==block.entry())
958 preceding_train = other_train;
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.endpoint();
993 bool multiple_paths = (track_ep.paths&(track_ep.paths-1));
995 if(multiple_paths && cur_route!=routes.end() && cur_route->diversion!=block->get_turnout_id())
996 /* There's multiple paths to be taken and we are on a route - take
997 note of the diversion possibility */
998 divert_track = &*track;
1001 if(!contested_blocks.empty() && contested_blocks.front()==block)
1002 contested_blocks.pop_front();
1004 blocks.push_back(block);
1006 if(cur_blocks_end==blocks.end())
1008 if(clear_blocks_end==blocks.end())
1010 if(good_end==blocks.end())
1013 if(block->get_sensor_id())
1016 dist += block->get_path_length(block.entry());
1019 // Unreserve blocks that were not good
1020 release_blocks(good_end, blocks.end());
1022 if(blocks.back()!=start)
1023 // We got some new blocks, so no longer need to yield
1026 check_turnout_paths(true);
1028 // Make any sensorless blocks at the beginning immediately current
1029 while(cur_blocks_end!=clear_blocks_end && !(*cur_blocks_end)->get_sensor_id())
1032 if(try_divert && divert(*divert_track))
1036 void Train::check_turnout_paths(bool set)
1038 if(clear_blocks_end==blocks.end())
1041 for(list<BlockIter>::iterator i=clear_blocks_end; i!=blocks.end(); ++i)
1043 if((*i)->get_turnout_id())
1045 TrackIter track = i->track_iter();
1046 const TrackType::Endpoint &track_ep = track.endpoint();
1049 list<BlockIter>::iterator j = i;
1050 if(++j!=blocks.end())
1052 TrackIter rev = j->track_iter().flip();
1053 unsigned mask = rev.endpoint().paths&track_ep.paths;
1054 for(path=0; mask>1; mask>>=1, ++path) ;
1059 if(path!=track->get_active_path())
1062 track->set_active_path(path);
1064 /* Check again, in case the driver was able to service the request
1066 if(!set || path!=track->get_active_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
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+1<real_speed.size(); ++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_step(float real) const
1166 if(real_speed.size()<=1)
1168 if(real<=real_speed[1].speed*0.5)
1174 for(unsigned i=0; (!high && i<real_speed.size()); ++i)
1175 if(real_speed[i].weight)
1178 if(real_speed[i].speed<real)
1185 unsigned limit = real_speed.size()/5;
1193 return min(min(static_cast<unsigned>(low*real/real_speed[low].speed), real_speed.size()-1), last+limit);
1196 float f = (real-real_speed[low].speed)/(real_speed[high].speed-real_speed[low].speed);
1197 return static_cast<unsigned>(low*(1-f)+high*f+0.5);
1200 float Train::get_travel_speed() const
1202 float speed = get_real_speed(current_speed_step);
1203 float scale = layout.get_catalogue().get_scale();
1204 return static_cast<int>(round(speed/scale*3.6/5))*5;
1207 void Train::set_status(const string &s)
1210 signal_status_changed.emit(s);
1213 void Train::release_blocks()
1215 release_blocks(blocks.begin(), blocks.end());
1218 void Train::release_blocks(BlockList::iterator begin, BlockList::iterator end)
1222 if(begin==cur_blocks_end)
1223 cur_blocks_end = end;
1224 if(begin==clear_blocks_end)
1225 clear_blocks_end = end;
1227 Block &block = **begin;
1228 blocks.erase(begin++);
1231 if(begin==blocks.end())
1232 end_of_route = false;
1236 void Train::reverse_blocks(BlockList &blks) const
1239 for(BlockList::iterator i=blks.begin(); i!=blks.end(); ++i)
1243 bool Train::advance_route(list<RouteRef>::iterator &iter, Track &track)
1245 while(iter!=routes.end() && !iter->route->has_track(track))
1247 if(iter==routes.end())
1250 list<RouteRef>::iterator next = iter;
1252 if(next!=routes.end() && next->diversion && next->route->has_track(track))
1258 Route *Train::create_lead_route(Route *lead, const Route *target)
1262 lead = new Route(layout);
1263 lead->set_name("Lead");
1264 lead->set_temporary(true);
1267 set<Track *> tracks;
1268 for(BlockList::iterator i=blocks.begin(); i!=blocks.end(); ++i)
1270 const set<Track *> &btracks = (*i)->get_tracks();
1271 for(set<Track *>::const_iterator j=btracks.begin(); j!=btracks.end(); ++j)
1272 if(!target || !target->has_track(**j))
1276 lead->add_tracks(tracks);
1281 bool Train::is_valid_diversion(const Route &diversion, const TrackIter &from)
1283 float diversion_len = 0;
1284 TrackLoopIter track1 = from;
1285 while(diversion.has_track(*track1))
1287 unsigned path = diversion.get_path(*track1);
1288 diversion_len += track1->get_type().get_path_length(path);
1290 track1 = track1.next(path);
1296 list<RouteRef>::iterator route = routes.begin();
1297 if(!advance_route(route, *from))
1300 float route_len = 0;
1301 TrackLoopIter track2 = from;
1304 unsigned path = route->route->get_path(*track2);
1305 route_len += track2->get_type().get_path_length(path);
1307 bool ok = (track2!=from && diversion.has_track(*track2));
1309 track2 = track2.next(path);
1317 if(!advance_route(route, *track2))
1321 // Must end up at the same place through both routes
1325 return diversion_len<route_len*1.2;
1329 Train::RouteRef::RouteRef(const Route *r, unsigned d):
1335 Train::RealSpeed::RealSpeed():
1340 void Train::RealSpeed::add(float s, float w)
1342 speed = (speed*weight+s*w)/(weight+w);
1343 weight = min(weight+w, 300.0f);
1347 Train::Loader::Loader(Train &t):
1348 DataFile::BasicLoader<Train>(t),
1352 add("block", &Loader::block);
1353 add("block_hint", &Loader::block_hint);
1354 add("name", &Loader::name);
1355 add("priority", &Train::priority);
1356 add("real_speed", &Loader::real_speed);
1357 add("route", &Loader::route);
1358 add("timetable", &Loader::timetable);
1359 add("vehicle", &Loader::vehicle);
1362 void Train::Loader::finish()
1364 if(!obj.blocks.empty())
1366 TrackIter track = obj.blocks.front().track_iter();
1367 float offset = 2*obj.layout.get_catalogue().get_scale();
1368 obj.vehicles.back()->place(*track, track.entry(), offset, Vehicle::BACK_BUFFER);
1370 obj.set_status("Stopped");
1374 void Train::Loader::block(unsigned id)
1382 blk = &obj.layout.get_block(id);
1384 catch(const KeyError &)
1386 blocks_valid = false;
1392 entry = blk->get_endpoint_by_link(*prev_block);
1397 obj.blocks.push_back(BlockIter(blk, entry));
1399 if(blk->get_sensor_id())
1400 obj.layout.get_driver().set_sensor(blk->get_sensor_id(), true);
1405 void Train::Loader::block_hint(unsigned id)
1409 prev_block = &obj.layout.get_block(id);
1411 catch(const KeyError &)
1413 blocks_valid = false;
1417 void Train::Loader::name(const string &n)
1422 void Train::Loader::real_speed(unsigned i, float speed, float weight)
1424 if(i>=obj.real_speed.size())
1426 obj.real_speed[i].speed = speed;
1427 obj.real_speed[i].weight = weight;
1430 void Train::Loader::route(const string &n)
1432 obj.set_route(&obj.layout.get_route(n));
1435 void Train::Loader::timetable()
1438 throw InvalidState("A timetable has already been loaded");
1440 obj.timetable = new Timetable(obj);
1441 load_sub(*obj.timetable);
1444 void Train::Loader::vehicle(ArticleNumber art_nr)
1446 const VehicleType &vtype = obj.layout.get_catalogue().get_vehicle(art_nr);
1447 Vehicle *veh = new Vehicle(obj.layout, vtype);
1448 obj.vehicles.back()->attach_back(*veh);
1449 obj.vehicles.push_back(veh);