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 && 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 for(BlockList::iterator j=cur_blocks_end; j!=end; ++j)
786 signal_advanced.emit(**j);
787 cur_blocks_end = end;
789 // Try to get more blocks if we're moving
794 layout.emergency("Sensor for "+name+" triggered out of order");
798 const Vehicle &veh = *(reverse ? vehicles.front() : vehicles.back());
800 // Find the first sensor in our current blocks that's still active
801 BlockList::iterator end = blocks.begin();
802 for(BlockList::iterator i=blocks.begin(); i!=cur_blocks_end; ++i)
804 if((*i)->has_track(*veh.get_track()))
806 if((*i)->get_sensor_id())
808 if(layout.get_driver().get_sensor((*i)->get_sensor_id()))
818 if(end!=blocks.begin() && end!=cur_blocks_end)
819 // Free blocks up to the last inactive sensor
820 release_blocks(blocks.begin(), end);
824 void Train::turnout_path_changed(Track &track)
826 for(list<BlockIter>::iterator i=blocks.begin(); i!=blocks.end(); ++i)
827 if((*i)->get_turnout_id()==track.get_turnout_id() && !reserving)
828 check_turnout_paths(false);
831 void Train::halt_event(bool h)
834 accurate_position = false;
837 void Train::block_reserved(const Block &block, const Train *train)
839 if(&block==pending_block && !train && !reserving)
843 void Train::reserve_more()
845 if(!active || blocks.empty() || end_of_route)
848 BlockIter start = blocks.back();
853 // See how many sensor blocks and how much track we already have
856 for(BlockList::const_iterator i=cur_blocks_end; i!=blocks.end(); ++i)
858 if((*i)->get_sensor_id())
861 dist += (*i)->get_path_length(i->entry());
864 list<RouteRef>::iterator cur_route = routes.begin();
865 advance_route(cur_route, *start.track_iter());
867 float approach_margin = 50*layout.get_catalogue().get_scale();
868 float min_dist = controller->get_braking_distance()*1.3+approach_margin*2;
870 BlockIter block = start;
871 list<BlockIter>::iterator good_end = blocks.end();
872 Track *divert_track = 0;
873 bool try_divert = false;
874 Train *blocking_train = 0;
875 BlockList contested_blocks;
877 SetFlag setf(reserving);
881 BlockIter last = block;
882 block = block.next(cur_route!=routes.end() ? cur_route->route : 0);
883 if(!block || block->get_endpoints().size()<2)
887 good_end = blocks.end();
893 TrackIter track = block.track_iter();
895 if(cur_route!=routes.end())
897 if(!advance_route(cur_route, *track))
899 // Keep the blocks if we arrived at the end of the route
902 good_end = blocks.end();
909 if(block->get_turnout_id() && !last->get_turnout_id())
911 /* We can keep the blocks if we arrive at a turnout from a non-turnout
912 block. Having a turnout block as our last reserved block is not good
913 as it would limit our diversion possibilities for little benefit. */
914 good_end = blocks.end();
915 if(nsens>=3 && dist>=min_dist)
921 if(block->get_train()!=blocking_train)
923 if(blocking_train->free_block(*contested_blocks.back()))
925 // Roll back and start actually reserving the blocks
926 block = blocks.back();
927 cur_route = routes.begin();
928 advance_route(cur_route, *block.track_iter().track());
929 if(blocking_train->get_priority()==priority)
930 blocking_train->yield_to(*this);
936 yield_to(*blocking_train);
937 pending_block = contested_blocks.front().block();
938 try_divert = divert_track;
944 contested_blocks.push_back(block);
949 bool reserved = block->reserve(this);
952 /* We've found another train. If it wants to exit the block from the
953 same endpoint we're trying to enter from or the other way around,
954 treat it as coming towards us. Otherwise treat it as going in the
956 Train *other_train = block->get_train();
957 int other_entry = other_train->get_entry_to_block(*block);
959 throw LogicError("Block reservation inconsistency");
961 unsigned exit = block.reverse().entry();
962 unsigned other_exit = BlockIter(block.block(), other_entry).reverse().entry();
963 bool entry_conflict = (block.entry()==other_exit);
964 bool exit_conflict = (exit==static_cast<unsigned>(other_entry));
965 if(!entry_conflict && !last->get_turnout_id())
967 /* The other train is not coming to the blocks we're holding, so we
969 good_end = blocks.end();
971 if(static_cast<unsigned>(other_entry)==block.entry())
972 preceding_train = other_train;
975 int other_prio = other_train->get_priority();
977 if(!entry_conflict && !exit_conflict && other_prio<priority)
979 /* Ask a lesser priority train going to the same direction to free
981 if(other_train->free_block(*block))
982 reserved = block->reserve(this);
984 else if(other_train!=yielding_to && (other_prio<priority || (other_prio==priority && entry_conflict)))
986 /* A lesser priority train is coming at us, we must ask it to free
987 enough blocks to get clear of it to avoid a potential deadlock */
988 blocking_train = other_train;
989 contested_blocks.clear();
990 contested_blocks.push_back(block);
993 else if(divert_track && (entry_conflict || exit_conflict || !other_train->is_active()))
994 // We are blocked, but there's a diversion possibility
999 pending_block = &*block;
1004 if(block->get_turnout_id())
1006 const TrackType::Endpoint &track_ep = track.endpoint();
1007 bool multiple_paths = (track_ep.paths&(track_ep.paths-1));
1009 if(multiple_paths && cur_route!=routes.end() && cur_route->diversion!=block->get_turnout_id())
1010 /* There's multiple paths to be taken and we are on a route - take
1011 note of the diversion possibility */
1012 divert_track = &*track;
1015 if(!contested_blocks.empty() && contested_blocks.front()==block)
1016 contested_blocks.pop_front();
1018 blocks.push_back(block);
1020 if(cur_blocks_end==blocks.end())
1022 if(clear_blocks_end==blocks.end())
1024 if(good_end==blocks.end())
1027 if(block->get_sensor_id())
1030 dist += block->get_path_length(block.entry());
1033 // Unreserve blocks that were not good
1034 release_blocks(good_end, blocks.end());
1036 if(blocks.back()!=start)
1037 // We got some new blocks, so no longer need to yield
1040 check_turnout_paths(true);
1042 // Make any sensorless blocks at the beginning immediately current
1043 while(cur_blocks_end!=clear_blocks_end && !(*cur_blocks_end)->get_sensor_id())
1046 if(try_divert && divert(*divert_track))
1050 void Train::check_turnout_paths(bool set)
1052 if(clear_blocks_end==blocks.end())
1055 for(list<BlockIter>::iterator i=clear_blocks_end; i!=blocks.end(); ++i)
1057 if((*i)->get_turnout_id())
1059 TrackIter track = i->track_iter();
1060 const TrackType::Endpoint &track_ep = track.endpoint();
1063 list<BlockIter>::iterator j = i;
1064 if(++j!=blocks.end())
1066 TrackIter rev = j->track_iter().flip();
1067 unsigned mask = rev.endpoint().paths&track_ep.paths;
1068 for(path=0; mask>1; mask>>=1, ++path) ;
1073 if(path!=track->get_active_path())
1076 track->set_active_path(path);
1078 /* Check again, in case the driver was able to service the request
1080 if(!set || path!=track->get_active_path())
1085 if(i==clear_blocks_end)
1090 float Train::get_reserved_distance_until(const Block *until_block, bool back) const
1095 Vehicle &veh = *(reverse!=back ? vehicles.back() : vehicles.front());
1096 const VehicleType &vtype = veh.get_type();
1098 TrackIter track(veh.get_track(), veh.get_entry());
1099 if(!track) // XXX Probably unnecessary
1102 BlockList::const_iterator block = blocks.begin();
1103 while(block!=clear_blocks_end && !(*block)->has_track(*track))
1105 if(block==clear_blocks_end || &**block==until_block)
1108 float result = veh.get_offset();
1110 track = track.reverse();
1112 result = track->get_type().get_path_length(track->get_active_path())-result;
1113 result -= vtype.get_length()/2;
1117 track = track.next();
1121 if(!(*block)->has_track(*track))
1125 if(block==blocks.begin())
1132 if(block==clear_blocks_end)
1136 if(&**block==until_block)
1140 result += track->get_type().get_path_length(track->get_active_path());
1146 float Train::get_real_speed(unsigned i) const
1150 if(real_speed[i].weight)
1151 return real_speed[i].speed;
1155 for(low=i; low>0; --low)
1156 if(real_speed[low].weight)
1158 for(high=i; high+1<real_speed.size(); ++high)
1159 if(real_speed[high].weight)
1162 if(real_speed[high].weight)
1164 if(real_speed[low].weight)
1166 float f = float(i-low)/(high-low);
1167 return real_speed[low].speed*(1-f)+real_speed[high].speed*f;
1170 return real_speed[high].speed*float(i)/high;
1172 else if(real_speed[low].weight)
1173 return real_speed[low].speed*float(i)/low;
1178 unsigned Train::find_speed_step(float real) const
1180 if(real_speed.size()<=1)
1182 if(real<=real_speed[1].speed*0.5)
1188 for(unsigned i=0; (!high && i<real_speed.size()); ++i)
1189 if(real_speed[i].weight)
1192 if(real_speed[i].speed>=real)
1194 else if(real_speed[i].speed>real_speed[low].speed)
1199 unsigned limit = real_speed.size()/5;
1207 return min(min(static_cast<unsigned>(low*real/real_speed[low].speed), real_speed.size()-1), last+limit);
1210 float f = (real-real_speed[low].speed)/(real_speed[high].speed-real_speed[low].speed);
1211 return static_cast<unsigned>(low*(1-f)+high*f+0.5);
1214 float Train::get_travel_speed() const
1216 float speed = get_real_speed(current_speed_step);
1217 float scale = layout.get_catalogue().get_scale();
1218 return static_cast<int>(round(speed/scale*3.6/5))*5;
1221 void Train::set_status(const string &s)
1224 signal_status_changed.emit(s);
1227 void Train::release_blocks()
1229 release_blocks(blocks.begin(), blocks.end());
1232 void Train::release_blocks(BlockList::iterator begin, BlockList::iterator end)
1236 if(begin==cur_blocks_end)
1237 cur_blocks_end = end;
1238 if(begin==clear_blocks_end)
1239 clear_blocks_end = end;
1241 Block &block = **begin;
1242 blocks.erase(begin++);
1245 if(begin==blocks.end())
1246 end_of_route = false;
1250 void Train::reverse_blocks(BlockList &blks) const
1253 for(BlockList::iterator i=blks.begin(); i!=blks.end(); ++i)
1257 bool Train::advance_route(list<RouteRef>::iterator &iter, Track &track)
1259 while(iter!=routes.end() && !iter->route->has_track(track))
1261 if(iter==routes.end())
1264 list<RouteRef>::iterator next = iter;
1266 if(next!=routes.end() && next->diversion && next->route->has_track(track))
1272 Route *Train::create_lead_route(Route *lead, const Route *target)
1276 lead = new Route(layout);
1277 lead->set_name("Lead");
1278 lead->set_temporary(true);
1281 set<Track *> tracks;
1282 for(BlockList::iterator i=blocks.begin(); i!=blocks.end(); ++i)
1284 const set<Track *> &btracks = (*i)->get_tracks();
1285 for(set<Track *>::const_iterator j=btracks.begin(); j!=btracks.end(); ++j)
1286 if(!target || !target->has_track(**j))
1290 lead->add_tracks(tracks);
1295 bool Train::is_valid_diversion(const Route &diversion, const TrackIter &from)
1297 float diversion_len = 0;
1298 TrackLoopIter track1 = from;
1299 while(diversion.has_track(*track1))
1301 unsigned path = diversion.get_path(*track1);
1302 diversion_len += track1->get_type().get_path_length(path);
1304 track1 = track1.next(path);
1306 if(!track1 || track1.looped())
1310 list<RouteRef>::iterator route = routes.begin();
1311 if(!advance_route(route, *from))
1314 float route_len = 0;
1315 TrackLoopIter track2 = from;
1318 unsigned path = route->route->get_path(*track2);
1319 route_len += track2->get_type().get_path_length(path);
1321 bool ok = (track2!=from && diversion.has_track(*track2));
1323 track2 = track2.next(path);
1333 if(!advance_route(route, *track2))
1337 // Must end up at the same place through both routes
1341 return diversion_len<route_len*1.2;
1345 Train::RouteRef::RouteRef(const Route *r, unsigned d):
1351 Train::RealSpeed::RealSpeed():
1356 void Train::RealSpeed::add(float s, float w)
1358 speed = (speed*weight+s*w)/(weight+w);
1359 weight = min(weight+w, 300.0f);
1363 Train::Loader::Loader(Train &t):
1364 DataFile::BasicLoader<Train>(t),
1368 add("block", &Loader::block);
1369 add("block_hint", &Loader::block_hint);
1370 add("name", &Loader::name);
1371 add("priority", &Train::priority);
1372 add("real_speed", &Loader::real_speed);
1373 add("route", &Loader::route);
1374 add("timetable", &Loader::timetable);
1375 add("vehicle", &Loader::vehicle);
1378 void Train::Loader::finish()
1380 if(!obj.blocks.empty())
1382 TrackIter track = obj.blocks.front().track_iter();
1383 float offset = 2*obj.layout.get_catalogue().get_scale();
1384 obj.vehicles.back()->place(*track, track.entry(), offset, Vehicle::BACK_BUFFER);
1386 obj.set_status("Stopped");
1390 void Train::Loader::block(unsigned id)
1398 blk = &obj.layout.get_block(id);
1400 catch(const KeyError &)
1402 blocks_valid = false;
1408 entry = blk->get_endpoint_by_link(*prev_block);
1413 obj.blocks.push_back(BlockIter(blk, entry));
1415 if(blk->get_sensor_id())
1416 obj.layout.get_driver().set_sensor(blk->get_sensor_id(), true);
1421 void Train::Loader::block_hint(unsigned id)
1425 prev_block = &obj.layout.get_block(id);
1427 catch(const KeyError &)
1429 blocks_valid = false;
1433 void Train::Loader::name(const string &n)
1438 void Train::Loader::real_speed(unsigned i, float speed, float weight)
1440 if(i>=obj.real_speed.size())
1442 obj.real_speed[i].speed = speed;
1443 obj.real_speed[i].weight = weight;
1446 void Train::Loader::route(const string &n)
1448 obj.set_route(&obj.layout.get_route(n));
1451 void Train::Loader::timetable()
1454 throw InvalidState("A timetable has already been loaded");
1456 obj.timetable = new Timetable(obj);
1457 load_sub(*obj.timetable);
1460 void Train::Loader::vehicle(ArticleNumber art_nr)
1462 const VehicleType &vtype = obj.layout.get_catalogue().get_vehicle(art_nr);
1463 Vehicle *veh = new Vehicle(obj.layout, vtype);
1464 obj.vehicles.back()->attach_back(*veh);
1465 obj.vehicles.push_back(veh);