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 if(get_reserved_distance_until(&block, false)<controller->get_braking_distance()*1.3)
450 for(BlockList::iterator i=cur_blocks_end; i!=blocks.end(); ++i)
452 if(i->block()==&block)
456 release_blocks(i, blocks.end());
459 else if((*i)->get_sensor_id())
466 void Train::free_noncritical_blocks()
471 if(controller->get_speed()==0)
473 release_blocks(cur_blocks_end, blocks.end());
477 float margin = 10*layout.get_catalogue().get_scale();
478 float min_dist = controller->get_braking_distance()*1.3+margin;
480 Vehicle &veh = *(reverse ? vehicles.back() : vehicles.front());
482 TrackIter track(veh.get_track(), veh.get_entry());
483 BlockList::iterator block = blocks.begin();
485 while(block!=blocks.end() && !(*block)->has_track(*track))
488 if(block==cur_blocks_end)
492 float dist = veh.get_offset();
496 dist = track->get_type().get_path_length(track->get_active_path())-dist;
497 dist -= veh.get_type().get_length()/2;
502 track = track.next();
504 if(!(*block)->has_track(*track))
507 if(block==cur_blocks_end)
509 if(block==blocks.end())
512 if(dist>min_dist && nsens>0)
514 release_blocks(block, blocks.end());
518 if(in_rsv && (*block)->get_sensor_id())
522 dist += track->get_type().get_path_length(track->get_active_path());
526 int Train::get_entry_to_block(Block &block) const
528 for(BlockList::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
529 if(i->block()==&block)
534 float Train::get_reserved_distance() const
540 TrackIter next = blocks.back().next().track_iter();
541 if(next->get_type().is_turnout())
542 margin = 15*layout.get_catalogue().get_scale();
544 return max(get_reserved_distance_until(0, false)-margin, 0.0f);
547 void Train::tick(const Time::TimeStamp &t, const Time::TimeDelta &dt)
549 if(!active && stop_timeout && t>=stop_timeout)
551 release_blocks(cur_blocks_end, blocks.end());
552 stop_timeout = Time::TimeStamp();
555 Driver &driver = layout.get_driver();
559 controller->tick(dt);
560 float speed = controller->get_speed();
561 unsigned speed_step = find_speed_step(speed);
563 if(controller->get_reverse()!=reverse)
565 reverse = controller->get_reverse();
566 driver.set_loco_reverse(address, reverse);
568 release_blocks(cur_blocks_end, blocks.end());
569 reverse_blocks(blocks);
573 if(speed_step!=current_speed_step && !speed_changing && !driver.is_halted() && driver.get_power())
575 speed_changing = true;
576 driver.set_loco_speed(address, speed_step);
581 set_status(format("Traveling %d kmh", get_travel_speed()));
583 set_status("Waiting");
591 Vehicle &vehicle = *(reverse ? vehicles.back() : vehicles.front());
592 Track *track = vehicle.get_track();
595 for(BlockList::const_iterator i=blocks.begin(); (!ok && i!=cur_blocks_end); ++i)
596 ok = (*i)->has_track(*track);
599 if(real_speed.size()>1)
600 d = get_real_speed(current_speed_step)*(dt/Time::sec);
602 d = speed*(dt/Time::sec);
605 SetFlag setf(advancing);
606 vehicle.advance(reverse ? -d : d);
608 else if(accurate_position)
611 if(overshoot_dist>40*layout.get_catalogue().get_scale())
613 layout.emergency(name+" has not arrived at sensor");
614 accurate_position = false;
618 else if(end_of_route && cur_blocks_end==blocks.end())
621 signal_arrived.emit();
625 if(!blocks.empty() && !blocks.front()->get_sensor_id())
627 float dist = get_reserved_distance_until(&*blocks.front(), true);
629 if(dist>10*layout.get_catalogue().get_scale())
631 blocks.front()->reserve(0);
637 void Train::save(list<DataFile::Statement> &st) const
639 st.push_back((DataFile::Statement("name"), name));
641 st.push_back((DataFile::Statement("priority"), priority));
643 for(vector<Vehicle *>::const_iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
644 if(i!=vehicles.begin())
645 st.push_back((DataFile::Statement("vehicle"), (*i)->get_type().get_article_number()));
647 for(unsigned i=0; i<real_speed.size(); ++i)
648 if(real_speed[i].weight)
649 st.push_back((DataFile::Statement("real_speed"), i, real_speed[i].speed, real_speed[i].weight));
651 if(!blocks.empty() && cur_blocks_end!=blocks.begin())
653 BlockList blks(blocks.begin(), BlockList::const_iterator(cur_blocks_end));
655 reverse_blocks(blks);
657 BlockIter prev = blks.front().flip();
658 st.push_back((DataFile::Statement("block_hint"), prev->get_id()));
660 for(BlockList::const_iterator i=blks.begin(); i!=blks.end(); ++i)
661 st.push_back((DataFile::Statement("block"), (*i)->get_id()));
666 list<RouteRef>::const_iterator i = routes.begin();
667 for(; (i!=routes.end() && i->route->is_temporary()); ++i) ;
669 st.push_back((DataFile::Statement("route"), i->route->get_name()));
674 DataFile::Statement ss("timetable");
675 timetable->save(ss.sub);
680 void Train::control_changed(const Controller::Control &ctrl)
682 signal_control_changed.emit(ctrl.name, ctrl.value);
685 void Train::loco_speed_event(unsigned addr, unsigned speed, bool rev)
689 current_speed_step = speed;
691 layout.get_driver().set_loco_reverse(address, reverse);
692 speed_changing = false;
697 void Train::loco_func_event(unsigned addr, unsigned func, bool state)
702 functions |= 1<<func;
704 functions &= ~(1<<func);
706 signal_function_changed.emit(func, state);
710 void Train::sensor_event(unsigned addr, bool state)
714 // Find the first sensor block from our reserved blocks that isn't this sensor
715 BlockList::iterator end;
717 for(end=cur_blocks_end; end!=blocks.end(); ++end)
718 if((*end)->get_sensor_id())
720 if((*end)->get_sensor_id()!=addr)
735 // Compute speed and update related state
736 float travel_time_secs = (Time::now()-last_entry_time)/Time::sec;
740 if(current_speed_step>0)
742 RealSpeed &rs = real_speed[current_speed_step];
743 rs.add(travel_dist/travel_time_secs, travel_time_secs);
745 set_status(format("Traveling %d kmh", get_travel_speed()));
749 for(BlockList::iterator j=cur_blocks_end; j!=end; ++j)
751 travel_dist += (*j)->get_path_length(j->entry());
753 if((*j)->get_sensor_id()==addr && !advancing)
755 TrackIter track = j->track_iter();
758 track = track.flip();
759 vehicles.back()->place(*track, track.entry(), 0, Vehicle::BACK_AXLE);
762 vehicles.front()->place(*track, track.entry(), 0, Vehicle::FRONT_AXLE);
765 last_entry_time = Time::now();
767 accurate_position = true;
770 // Check if we've reached the next route
773 const Route &route = *(++routes.begin())->route;
774 for(BlockList::iterator j=cur_blocks_end; j!=end; ++j)
775 if(route.has_track(*j->track_iter()))
779 signal_route_changed.emit(routes.front().route);
784 // Move blocks up to the next sensor to our current blocks
785 cur_blocks_end = end;
787 // Try to get more blocks if we're moving
792 layout.emergency("Sensor for "+name+" triggered out of order");
796 const Vehicle &veh = *(reverse ? vehicles.front() : vehicles.back());
798 // Find the first sensor in our current blocks that's still active
799 BlockList::iterator end = blocks.begin();
800 for(BlockList::iterator i=blocks.begin(); i!=cur_blocks_end; ++i)
802 if((*i)->has_track(*veh.get_track()))
804 if((*i)->get_sensor_id())
806 if(layout.get_driver().get_sensor((*i)->get_sensor_id()))
816 if(end!=blocks.begin() && end!=cur_blocks_end)
817 // Free blocks up to the last inactive sensor
818 release_blocks(blocks.begin(), end);
822 void Train::turnout_path_changed(Track &track)
824 for(list<BlockIter>::iterator i=blocks.begin(); i!=blocks.end(); ++i)
825 if((*i)->get_turnout_id()==track.get_turnout_id() && !reserving)
826 check_turnout_paths(false);
829 void Train::halt_event(bool h)
832 accurate_position = false;
835 void Train::block_reserved(const Block &block, const Train *train)
837 if(&block==pending_block && !train && !reserving)
841 void Train::reserve_more()
843 if(!active || blocks.empty() || end_of_route)
846 BlockIter start = blocks.back();
851 // See how many sensor blocks and how much track we already have
854 for(BlockList::const_iterator i=cur_blocks_end; i!=blocks.end(); ++i)
856 if((*i)->get_sensor_id())
859 dist += (*i)->get_path_length(i->entry());
862 list<RouteRef>::iterator cur_route = routes.begin();
863 advance_route(cur_route, *start.track_iter());
865 float approach_margin = 50*layout.get_catalogue().get_scale();
866 float min_dist = controller->get_braking_distance()*1.3+approach_margin*2;
868 BlockIter block = start;
869 list<BlockIter>::iterator good_end = blocks.end();
870 Track *divert_track = 0;
871 bool try_divert = false;
872 Train *blocking_train = 0;
873 BlockList contested_blocks;
875 SetFlag setf(reserving);
879 BlockIter last = block;
880 block = block.next(cur_route!=routes.end() ? cur_route->route : 0);
881 if(!block || block->get_endpoints().size()<2)
885 good_end = blocks.end();
891 TrackIter track = block.track_iter();
893 if(cur_route!=routes.end())
895 if(!advance_route(cur_route, *track))
897 // Keep the blocks if we arrived at the end of the route
900 good_end = blocks.end();
907 if(block->get_turnout_id() && !last->get_turnout_id())
909 /* We can keep the blocks if we arrive at a turnout from a non-turnout
910 block. Having a turnout block as our last reserved block is not good
911 as it would limit our diversion possibilities for little benefit. */
912 good_end = blocks.end();
913 if(nsens>=3 && dist>=min_dist)
919 if(block->get_train()!=blocking_train)
921 if(blocking_train->free_block(*contested_blocks.back()))
923 // Roll back and start actually reserving the blocks
924 block = blocks.back();
925 cur_route = routes.begin();
926 advance_route(cur_route, *block.track_iter().track());
927 if(blocking_train->get_priority()==priority)
928 blocking_train->yield_to(*this);
934 yield_to(*blocking_train);
935 pending_block = contested_blocks.front().block();
936 try_divert = divert_track;
942 contested_blocks.push_back(block);
947 bool reserved = block->reserve(this);
950 /* We've found another train. If it wants to exit the block from the
951 same endpoint we're trying to enter from or the other way around,
952 treat it as coming towards us. Otherwise treat it as going in the
954 Train *other_train = block->get_train();
955 int other_entry = other_train->get_entry_to_block(*block);
957 throw LogicError("Block reservation inconsistency");
959 unsigned exit = block.reverse().entry();
960 unsigned other_exit = BlockIter(block.block(), other_entry).reverse().entry();
961 bool entry_conflict = (block.entry()==other_exit);
962 bool exit_conflict = (exit==static_cast<unsigned>(other_entry));
963 if(!entry_conflict && !last->get_turnout_id())
965 /* The other train is not coming to the blocks we're holding, so we
967 good_end = blocks.end();
969 if(static_cast<unsigned>(other_entry)==block.entry())
970 preceding_train = other_train;
973 int other_prio = other_train->get_priority();
975 if(!entry_conflict && !exit_conflict && other_prio<priority)
977 /* Ask a lesser priority train going to the same direction to free
979 if(other_train->free_block(*block))
980 reserved = block->reserve(this);
982 else if(other_train!=yielding_to && (other_prio<priority || (other_prio==priority && entry_conflict)))
984 /* A lesser priority train is coming at us, we must ask it to free
985 enough blocks to get clear of it to avoid a potential deadlock */
986 blocking_train = other_train;
987 contested_blocks.clear();
988 contested_blocks.push_back(block);
991 else if(divert_track && (entry_conflict || exit_conflict || !other_train->is_active()))
992 // We are blocked, but there's a diversion possibility
997 pending_block = &*block;
1002 if(block->get_turnout_id())
1004 const TrackType::Endpoint &track_ep = track.endpoint();
1005 bool multiple_paths = (track_ep.paths&(track_ep.paths-1));
1007 if(multiple_paths && cur_route!=routes.end() && cur_route->diversion!=block->get_turnout_id())
1008 /* There's multiple paths to be taken and we are on a route - take
1009 note of the diversion possibility */
1010 divert_track = &*track;
1013 if(!contested_blocks.empty() && contested_blocks.front()==block)
1014 contested_blocks.pop_front();
1016 blocks.push_back(block);
1018 if(cur_blocks_end==blocks.end())
1020 if(clear_blocks_end==blocks.end())
1022 if(good_end==blocks.end())
1025 if(block->get_sensor_id())
1028 dist += block->get_path_length(block.entry());
1031 // Unreserve blocks that were not good
1032 release_blocks(good_end, blocks.end());
1034 if(blocks.back()!=start)
1035 // We got some new blocks, so no longer need to yield
1038 check_turnout_paths(true);
1040 // Make any sensorless blocks at the beginning immediately current
1041 while(cur_blocks_end!=clear_blocks_end && !(*cur_blocks_end)->get_sensor_id())
1044 if(try_divert && divert(*divert_track))
1048 void Train::check_turnout_paths(bool set)
1050 if(clear_blocks_end==blocks.end())
1053 for(list<BlockIter>::iterator i=clear_blocks_end; i!=blocks.end(); ++i)
1055 if((*i)->get_turnout_id())
1057 TrackIter track = i->track_iter();
1058 const TrackType::Endpoint &track_ep = track.endpoint();
1061 list<BlockIter>::iterator j = i;
1062 if(++j!=blocks.end())
1064 TrackIter rev = j->track_iter().flip();
1065 unsigned mask = rev.endpoint().paths&track_ep.paths;
1066 for(path=0; mask>1; mask>>=1, ++path) ;
1071 if(path!=track->get_active_path())
1074 track->set_active_path(path);
1076 /* Check again, in case the driver was able to service the request
1078 if(!set || path!=track->get_active_path())
1083 if(i==clear_blocks_end)
1088 float Train::get_reserved_distance_until(const Block *until_block, bool back) const
1093 Vehicle &veh = *(reverse!=back ? vehicles.back() : vehicles.front());
1094 const VehicleType &vtype = veh.get_type();
1096 TrackIter track(veh.get_track(), veh.get_entry());
1097 if(!track) // XXX Probably unnecessary
1100 BlockList::const_iterator block = blocks.begin();
1101 while(block!=clear_blocks_end && !(*block)->has_track(*track))
1103 if(block==clear_blocks_end || &**block==until_block)
1106 float result = veh.get_offset();
1108 track = track.reverse();
1110 result = track->get_type().get_path_length(track->get_active_path())-result;
1111 result -= vtype.get_length()/2;
1115 track = track.next();
1119 if(!(*block)->has_track(*track))
1123 if(block==blocks.begin())
1130 if(block==clear_blocks_end)
1134 if(&**block==until_block)
1138 result += track->get_type().get_path_length(track->get_active_path());
1144 float Train::get_real_speed(unsigned i) const
1148 if(real_speed[i].weight)
1149 return real_speed[i].speed;
1153 for(low=i; low>0; --low)
1154 if(real_speed[low].weight)
1156 for(high=i; high+1<real_speed.size(); ++high)
1157 if(real_speed[high].weight)
1160 if(real_speed[high].weight)
1162 if(real_speed[low].weight)
1164 float f = float(i-low)/(high-low);
1165 return real_speed[low].speed*(1-f)+real_speed[high].speed*f;
1168 return real_speed[high].speed*float(i)/high;
1170 else if(real_speed[low].weight)
1171 return real_speed[low].speed*float(i)/low;
1176 unsigned Train::find_speed_step(float real) const
1178 if(real_speed.size()<=1)
1180 if(real<=real_speed[1].speed*0.5)
1186 for(unsigned i=0; (!high && i<real_speed.size()); ++i)
1187 if(real_speed[i].weight)
1190 if(real_speed[i].speed>=real)
1192 else if(real_speed[i].speed>real_speed[low].speed)
1197 unsigned limit = real_speed.size()/5;
1205 return min(min(static_cast<unsigned>(low*real/real_speed[low].speed), real_speed.size()-1), last+limit);
1208 float f = (real-real_speed[low].speed)/(real_speed[high].speed-real_speed[low].speed);
1209 return static_cast<unsigned>(low*(1-f)+high*f+0.5);
1212 float Train::get_travel_speed() const
1214 float speed = get_real_speed(current_speed_step);
1215 float scale = layout.get_catalogue().get_scale();
1216 return static_cast<int>(round(speed/scale*3.6/5))*5;
1219 void Train::set_status(const string &s)
1222 signal_status_changed.emit(s);
1225 void Train::release_blocks()
1227 release_blocks(blocks.begin(), blocks.end());
1230 void Train::release_blocks(BlockList::iterator begin, BlockList::iterator end)
1234 if(begin==cur_blocks_end)
1235 cur_blocks_end = end;
1236 if(begin==clear_blocks_end)
1237 clear_blocks_end = end;
1239 Block &block = **begin;
1240 blocks.erase(begin++);
1243 if(begin==blocks.end())
1244 end_of_route = false;
1248 void Train::reverse_blocks(BlockList &blks) const
1251 for(BlockList::iterator i=blks.begin(); i!=blks.end(); ++i)
1255 bool Train::advance_route(list<RouteRef>::iterator &iter, Track &track)
1257 while(iter!=routes.end() && !iter->route->has_track(track))
1259 if(iter==routes.end())
1262 list<RouteRef>::iterator next = iter;
1264 if(next!=routes.end() && next->diversion && next->route->has_track(track))
1270 Route *Train::create_lead_route(Route *lead, const Route *target)
1274 lead = new Route(layout);
1275 lead->set_name("Lead");
1276 lead->set_temporary(true);
1279 set<Track *> tracks;
1280 for(BlockList::iterator i=blocks.begin(); i!=blocks.end(); ++i)
1282 const set<Track *> &btracks = (*i)->get_tracks();
1283 for(set<Track *>::const_iterator j=btracks.begin(); j!=btracks.end(); ++j)
1284 if(!target || !target->has_track(**j))
1288 lead->add_tracks(tracks);
1293 bool Train::is_valid_diversion(const Route &diversion, const TrackIter &from)
1295 float diversion_len = 0;
1296 TrackLoopIter track1 = from;
1297 while(diversion.has_track(*track1))
1299 unsigned path = diversion.get_path(*track1);
1300 diversion_len += track1->get_type().get_path_length(path);
1302 track1 = track1.next(path);
1304 if(!track1 || track1.looped())
1308 list<RouteRef>::iterator route = routes.begin();
1309 if(!advance_route(route, *from))
1312 float route_len = 0;
1313 TrackLoopIter track2 = from;
1316 unsigned path = route->route->get_path(*track2);
1317 route_len += track2->get_type().get_path_length(path);
1319 bool ok = (track2!=from && diversion.has_track(*track2));
1321 track2 = track2.next(path);
1331 if(!advance_route(route, *track2))
1335 // Must end up at the same place through both routes
1339 return diversion_len<route_len*1.2;
1343 Train::RouteRef::RouteRef(const Route *r, unsigned d):
1349 Train::RealSpeed::RealSpeed():
1354 void Train::RealSpeed::add(float s, float w)
1356 speed = (speed*weight+s*w)/(weight+w);
1357 weight = min(weight+w, 300.0f);
1361 Train::Loader::Loader(Train &t):
1362 DataFile::BasicLoader<Train>(t),
1366 add("block", &Loader::block);
1367 add("block_hint", &Loader::block_hint);
1368 add("name", &Loader::name);
1369 add("priority", &Train::priority);
1370 add("real_speed", &Loader::real_speed);
1371 add("route", &Loader::route);
1372 add("timetable", &Loader::timetable);
1373 add("vehicle", &Loader::vehicle);
1376 void Train::Loader::finish()
1378 if(!obj.blocks.empty())
1380 TrackIter track = obj.blocks.front().track_iter();
1381 float offset = 2*obj.layout.get_catalogue().get_scale();
1382 obj.vehicles.back()->place(*track, track.entry(), offset, Vehicle::BACK_BUFFER);
1384 obj.set_status("Stopped");
1388 void Train::Loader::block(unsigned id)
1396 blk = &obj.layout.get_block(id);
1398 catch(const KeyError &)
1400 blocks_valid = false;
1406 entry = blk->get_endpoint_by_link(*prev_block);
1411 obj.blocks.push_back(BlockIter(blk, entry));
1413 if(blk->get_sensor_id())
1414 obj.layout.get_driver().set_sensor(blk->get_sensor_id(), true);
1419 void Train::Loader::block_hint(unsigned id)
1423 prev_block = &obj.layout.get_block(id);
1425 catch(const KeyError &)
1427 blocks_valid = false;
1431 void Train::Loader::name(const string &n)
1436 void Train::Loader::real_speed(unsigned i, float speed, float weight)
1438 if(i>=obj.real_speed.size())
1440 obj.real_speed[i].speed = speed;
1441 obj.real_speed[i].weight = weight;
1444 void Train::Loader::route(const string &n)
1446 obj.set_route(&obj.layout.get_route(n));
1449 void Train::Loader::timetable()
1452 throw InvalidState("A timetable has already been loaded");
1454 obj.timetable = new Timetable(obj);
1455 load_sub(*obj.timetable);
1458 void Train::Loader::vehicle(ArticleNumber art_nr)
1460 const VehicleType &vtype = obj.layout.get_catalogue().get_vehicle(art_nr);
1461 Vehicle *veh = new Vehicle(obj.layout, vtype);
1462 obj.vehicles.back()->attach_back(*veh);
1463 obj.vehicles.push_back(veh);