3 #include <msp/core/maputils.h>
4 #include <msp/strings/format.h>
5 #include <msp/time/units.h>
6 #include <msp/time/utils.h>
12 #include "simplecontroller.h"
13 #include "speedquantizer.h"
14 #include "timetable.h"
15 #include "trackiter.h"
16 #include "tracktype.h"
19 #include "vehicletype.h"
31 SetFlag(bool &f): flag(f) { flag = true; }
32 ~SetFlag() { flag = false; }
40 Train::Train(Layout &l, const VehicleType &t, unsigned a, const string &p):
48 cur_blocks_end(blocks.end()),
49 clear_blocks_end(blocks.end()),
53 controller(new SimpleController),
55 current_speed_step(0),
56 speed_changing(false),
63 accurate_position(false),
66 if(!loco_type.is_locomotive())
67 throw invalid_argument("Train::Train");
69 unsigned speed_steps = layout.get_driver().get_protocol_speed_steps(protocol);
71 speed_quantizer = new SpeedQuantizer(speed_steps);
73 vehicles.push_back(new Vehicle(layout, loco_type));
75 layout.add_train(*this);
77 layout.get_driver().add_loco(address, protocol, loco_type);
78 layout.get_driver().signal_loco_speed.connect(sigc::mem_fun(this, &Train::loco_speed_event));
79 layout.get_driver().signal_loco_function.connect(sigc::mem_fun(this, &Train::loco_func_event));
81 layout.signal_block_reserved.connect(sigc::mem_fun(this, &Train::block_reserved));
82 layout.signal_block_state_changed.connect(sigc::mem_fun(this, &Train::block_state_changed));
84 layout.get_driver().signal_halt.connect(sigc::mem_fun(this, &Train::halt_event));
86 const set<Track *> &tracks = layout.get_tracks();
87 for(set<Track *>::const_iterator i=tracks.begin(); i!=tracks.end(); ++i)
88 if((*i)->get_turnout_id())
89 (*i)->signal_path_changed.connect(sigc::hide(sigc::bind(sigc::mem_fun(this, &Train::turnout_path_changed), sigc::ref(**i))));
91 controller->signal_control_changed.connect(sigc::mem_fun(this, &Train::control_changed));
97 for(vector<Vehicle *>::iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
99 layout.remove_train(*this);
102 void Train::set_name(const string &n)
106 signal_name_changed.emit(name);
109 void Train::set_priority(int p)
114 void Train::yield_to(const Train &t)
119 void Train::add_vehicle(const VehicleType &vt)
121 Vehicle *veh = new Vehicle(layout, vt);
122 vehicles.back()->attach_back(*veh);
123 vehicles.push_back(veh);
126 void Train::remove_vehicle(unsigned i)
128 if(i>=vehicles.size())
129 throw out_of_range("Train::remove_vehicle");
131 throw logic_error("can't remove locomotive");
133 vehicles.erase(vehicles.begin()+i);
134 if(i<vehicles.size())
135 vehicles[i-1]->attach_back(*vehicles[i]);
138 unsigned Train::get_n_vehicles() const
140 return vehicles.size();
143 Vehicle &Train::get_vehicle(unsigned i)
145 if(i>=vehicles.size())
146 throw out_of_range("Train::get_vehicle");
150 const Vehicle &Train::get_vehicle(unsigned i) const
152 if(i>=vehicles.size())
153 throw out_of_range("Train::get_vehicle");
157 void Train::set_control(const string &n, float v)
159 controller->set_control(n, v);
162 void Train::set_active(bool a)
166 if(!a && controller->get_speed())
167 throw logic_error("moving");
172 stop_timeout = Time::TimeStamp();
176 stop_timeout = Time::now()+2*Time::sec;
179 void Train::set_function(unsigned func, bool state)
181 if(!loco_type.get_functions().count(func))
182 throw invalid_argument("Train::set_function");
183 layout.get_driver().set_loco_function(address, func, state);
186 float Train::get_control(const string &ctrl) const
188 return controller->get_control(ctrl).value;
191 float Train::get_speed() const
193 return controller->get_speed();
196 float Train::get_quantized_speed() const
199 return speed_quantizer->quantize_speed(controller->get_speed());
201 return controller->get_speed();
204 bool Train::get_function(unsigned func) const
206 return (functions>>func)&1;
209 void Train::add_ai(TrainAI &ai)
212 ai.signal_event.connect(sigc::bind<0>(signal_ai_event, sigc::ref(ai)));
215 void Train::remove_ai(TrainAI &ai)
217 list<TrainAI *>::iterator i = find(ais.begin(), ais.end(), &ai);
222 TrainAI *Train::get_tagged_ai(const string &tag) const
224 for(list<TrainAI *>::const_iterator i=ais.begin(); i!=ais.end(); ++i)
225 if((*i)->get_tag()==tag)
231 void Train::ai_message(const TrainAI::Message &msg)
233 for(list<TrainAI *>::iterator i=ais.begin(); i!=ais.end(); ++i)
237 bool Train::set_route(const Route *r)
239 free_noncritical_blocks();
242 if(r && !blocks.empty())
244 TrackIter first = blocks.front().track_iter();
245 TrackIter next = blocks.back().next().track_iter();
246 if(!r->has_track(*next))
248 lead = Route::find(next, *r);
251 create_lead_route(lead, lead);
252 routes.push_front(lead);
254 else if(!r->has_track(*first))
255 lead = create_lead_route(0, r);
260 routes.push_back(lead);
263 end_of_route = false;
267 signal_route_changed.emit(get_route());
272 bool Train::go_to(Track &to)
274 for(BlockList::const_iterator i=blocks.begin(); i!=cur_blocks_end; ++i)
275 if((*i)->has_track(to))
277 signal_arrived.emit();
281 free_noncritical_blocks();
283 TrackIter next = blocks.back().next().track_iter();
285 Route *route = Route::find(next, to);
288 create_lead_route(route, route);
289 return set_route(route);
292 bool Train::go_to(const Zone &to)
295 for(BlockList::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
296 tracks.insert((*i)->get_tracks().begin(), (*i)->get_tracks().end());
298 const Zone::TrackSet &ztracks = to.get_tracks();
299 unsigned union_size = 0;
300 for(Zone::TrackSet::const_iterator i=ztracks.begin(); i!=ztracks.end(); ++i)
301 union_size += tracks.count(*i);
303 if(union_size==tracks.size() || union_size==ztracks.size())
305 signal_arrived.emit();
309 free_noncritical_blocks();
311 TrackIter next = blocks.back().next().track_iter();
313 Route *route = Route::find(next, to);
316 create_lead_route(route, route);
317 route->add_tracks(ztracks);
318 return set_route(route);
321 bool Train::divert(Track &from)
323 if(!from.get_turnout_id())
324 throw invalid_argument("Train::divert");
330 list<RouteRef>::iterator route = routes.begin();
332 // Follow our routes to find out where we're entering the turnout
333 for(TrackLoopIter track = blocks.front().track_iter();;)
335 if(!advance_route(route, *track))
340 Block &block = track->get_block();
341 if(block.get_train()==this && !free_block(block))
344 int route_path = route->route->get_turnout(from.get_turnout_id());
346 // Check that more than one path is available
347 unsigned ep_paths = track.endpoint().paths;
348 if(!(ep_paths&(ep_paths-1)))
351 // Choose some other path
352 for(int i=0; ep_paths>>i; ++i)
353 if((ep_paths&(1<<i)) && i!=route_path)
359 entry = track.entry();
363 track = track.next(route->route->get_path(*track));
365 if(!track || track.looped())
369 TrackIter track = TrackIter(&from, entry).next(path);
374 for(list<RouteRef>::iterator i=routes.begin(); i!=routes.end(); ++i)
375 tracks.insert(i->route->get_tracks().begin(), i->route->get_tracks().end());
376 RefPtr<Route> diversion = Route::find(track, tracks);
380 diversion->set_name("Diversion");
381 diversion->add_track(from);
382 diversion->set_turnout(from.get_turnout_id(), path);
384 if(!is_valid_diversion(*diversion, TrackIter(&from, entry)))
387 // Follow the diversion route until we get back to the original route
388 list<RouteRef>::iterator end = routes.end();
391 for(list<RouteRef>::iterator i=route; (end==routes.end() && i!=routes.end()); ++i)
392 if(i->route->has_track(*track))
395 if(end!=routes.end())
397 else if(!diversion->has_track(*track))
398 throw logic_error("bad diversion");
400 track = track.next(diversion->get_path(*track));
404 // We are rejoining the same route we diverted from, duplicate it
405 routes.insert(end, *route);
409 routes.erase(route, end);
411 routes.insert(end, RouteRef(diversion.release(), from.get_turnout_id()));
416 const Route *Train::get_route() const
420 return routes.front().route;
423 void Train::place(Block &block, unsigned entry)
425 if(controller->get_speed())
426 throw logic_error("moving");
431 accurate_position = false;
433 if(!block.reserve(this))
436 blocks.push_back(BlockIter(&block, entry));
439 TrackIter track = BlockIter(&block, entry).reverse().track_iter();
440 vehicles.front()->place(*track, track.entry(), 0, Vehicle::FRONT_BUFFER);
444 const Block::Endpoint &bep = block.get_endpoint(entry);
445 vehicles.back()->place(*bep.track, bep.track_ep, 0, Vehicle::BACK_BUFFER);
449 void Train::unplace()
451 if(controller->get_speed())
452 throw logic_error("moving");
457 accurate_position = false;
459 for(vector<Vehicle *>::iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
463 bool Train::free_block(Block &block)
465 if(get_reserved_distance_until(&block, false)<controller->get_braking_distance()*1.3)
469 for(BlockList::iterator i=cur_blocks_end; i!=blocks.end(); ++i)
471 if(i->block()==&block)
475 release_blocks(i, blocks.end());
478 else if((*i)->get_sensor_id())
485 void Train::free_noncritical_blocks()
490 if(controller->get_speed()==0)
492 release_blocks(cur_blocks_end, blocks.end());
496 float margin = 10*layout.get_catalogue().get_scale();
497 float min_dist = controller->get_braking_distance()*1.3+margin;
499 Vehicle &veh = *(reverse ? vehicles.back() : vehicles.front());
501 TrackIter track(veh.get_track(), veh.get_entry());
502 BlockList::iterator block = blocks.begin();
504 while(block!=blocks.end() && !(*block)->has_track(*track))
507 if(block==cur_blocks_end)
511 float dist = veh.get_offset();
515 dist = track->get_type().get_path_length(track->get_active_path())-dist;
516 dist -= veh.get_type().get_length()/2;
521 track = track.next();
523 if(!(*block)->has_track(*track))
526 if(block==cur_blocks_end)
528 if(block==blocks.end())
531 if(dist>min_dist && nsens>0)
533 release_blocks(block, blocks.end());
537 if(in_rsv && (*block)->get_sensor_id())
541 dist += track->get_type().get_path_length(track->get_active_path());
545 int Train::get_entry_to_block(Block &block) const
547 for(BlockList::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
548 if(i->block()==&block)
553 float Train::get_reserved_distance() const
559 TrackIter next = blocks.back().next().track_iter();
560 if(next && next->get_type().is_turnout())
561 margin = 15*layout.get_catalogue().get_scale();
563 return max(get_reserved_distance_until(0, false)-margin, 0.0f);
566 void Train::tick(const Time::TimeStamp &t, const Time::TimeDelta &dt)
568 if(!active && stop_timeout && t>=stop_timeout)
570 release_blocks(cur_blocks_end, blocks.end());
571 stop_timeout = Time::TimeStamp();
574 Driver &driver = layout.get_driver();
576 for(list<TrainAI *>::iterator i=ais.begin(); i!=ais.end(); ++i)
578 controller->tick(dt);
579 float speed = controller->get_speed();
580 bool moving = speed>0;
582 if(controller->get_reverse()!=reverse)
584 reverse = controller->get_reverse();
586 if(loco_type.get_swap_direction())
588 driver.set_loco_reverse(address, r);
590 release_blocks(cur_blocks_end, blocks.end());
591 reverse_blocks(blocks);
598 unsigned speed_step = speed_quantizer->find_speed_step(speed);
599 if(speed_step!=current_speed_step && !speed_changing && !driver.is_halted() && driver.get_power())
601 speed_changing = true;
602 driver.set_loco_speed(address, speed_step);
607 speed = speed_quantizer->get_speed(current_speed_step);
615 Vehicle &vehicle = *(reverse ? vehicles.back() : vehicles.front());
616 Track *track = vehicle.get_track();
619 for(BlockList::const_iterator i=blocks.begin(); (!ok && i!=cur_blocks_end); ++i)
620 ok = (*i)->has_track(*track);
622 float d = speed*(dt/Time::sec);
625 SetFlag setf(advancing);
626 vehicle.advance(reverse ? -d : d);
628 else if(accurate_position)
631 if(overshoot_dist>40*layout.get_catalogue().get_scale())
633 layout.emergency(name+" has not arrived at sensor");
634 accurate_position = false;
638 else if(end_of_route && cur_blocks_end==blocks.end())
641 signal_arrived.emit();
645 if(!blocks.empty() && !blocks.front()->get_sensor_id())
647 float dist = get_reserved_distance_until(&*blocks.front(), true);
649 if(dist>10*layout.get_catalogue().get_scale())
651 blocks.front()->reserve(0);
657 void Train::save(list<DataFile::Statement> &st) const
659 st.push_back((DataFile::Statement("name"), name));
661 st.push_back((DataFile::Statement("priority"), priority));
663 for(vector<Vehicle *>::const_iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
664 if(i!=vehicles.begin())
665 st.push_back((DataFile::Statement("vehicle"), (*i)->get_type().get_article_number()));
669 DataFile::Statement ss("quantized_speed");
670 speed_quantizer->save(ss.sub);
674 if(!blocks.empty() && cur_blocks_end!=blocks.begin())
676 BlockList blks(blocks.begin(), BlockList::const_iterator(cur_blocks_end));
678 reverse_blocks(blks);
680 BlockIter prev = blks.front().flip();
681 st.push_back((DataFile::Statement("block_hint"), prev->get_id()));
683 for(BlockList::const_iterator i=blks.begin(); i!=blks.end(); ++i)
684 st.push_back((DataFile::Statement("block"), (*i)->get_id()));
689 list<RouteRef>::const_iterator i = routes.begin();
690 for(; (i!=routes.end() && i->route->is_temporary()); ++i) ;
692 st.push_back((DataFile::Statement("route"), i->route->get_name()));
695 // XXX Need more generic way of saving AI state
696 for(list<TrainAI *>::const_iterator i=ais.begin(); i!=ais.end(); ++i)
697 if(Timetable *timetable = dynamic_cast<Timetable *>(*i))
699 DataFile::Statement ss("timetable");
700 timetable->save(ss.sub);
705 void Train::control_changed(const Controller::Control &ctrl)
707 signal_control_changed.emit(ctrl.name, ctrl.value);
710 void Train::loco_speed_event(unsigned addr, unsigned speed, bool rev)
714 current_speed_step = speed;
716 if(loco_type.get_swap_direction())
719 layout.get_driver().set_loco_reverse(address, r);
720 speed_changing = false;
725 void Train::loco_func_event(unsigned addr, unsigned func, bool state)
730 functions |= 1<<func;
732 functions &= ~(1<<func);
734 signal_function_changed.emit(func, state);
738 void Train::block_state_changed(Block &block, Block::State state)
740 if(state==Block::MAYBE_ACTIVE)
742 // Find the first sensor block from our reserved blocks that isn't this sensor
743 BlockList::iterator end;
745 for(end=cur_blocks_end; end!=blocks.end(); ++end)
746 if((*end)->get_sensor_id())
763 // Compute speed and update related state
764 float travel_time_secs = (Time::now()-last_entry_time)/Time::sec;
766 if(pure_speed && speed_quantizer && current_speed_step>0 && travel_time_secs>=2)
767 speed_quantizer->learn(current_speed_step, travel_dist/travel_time_secs, travel_time_secs);
770 for(BlockList::iterator j=cur_blocks_end; j!=end; ++j)
772 travel_dist += (*j)->get_path_length(j->entry());
774 if(&**j==&block && !advancing)
776 TrackIter track = j->track_iter();
779 track = track.flip();
780 vehicles.back()->place(*track, track.entry(), 0, Vehicle::BACK_AXLE);
783 vehicles.front()->place(*track, track.entry(), 0, Vehicle::FRONT_AXLE);
786 last_entry_time = Time::now();
788 accurate_position = true;
791 // Check if we've reached the next route
794 const Route &route = *(++routes.begin())->route;
795 for(BlockList::iterator j=cur_blocks_end; j!=end; ++j)
796 if(route.has_track(*j->track_iter()))
800 signal_route_changed.emit(routes.front().route);
805 // Move blocks up to the next sensor to our current blocks
806 for(BlockList::iterator j=cur_blocks_end; j!=end; ++j)
807 signal_advanced.emit(**j);
808 cur_blocks_end = end;
810 // Try to get more blocks if we're moving
815 layout.emergency("Sensor for "+name+" triggered out of order");
817 else if(state==Block::INACTIVE)
819 const Vehicle &veh = *(reverse ? vehicles.front() : vehicles.back());
821 // Find the first sensor in our current blocks that's still active
822 BlockList::iterator end = blocks.begin();
823 for(BlockList::iterator i=blocks.begin(); i!=cur_blocks_end; ++i)
825 if((*i)->has_track(*veh.get_track()))
827 if((*i)->get_sensor_id())
829 if(layout.get_driver().get_sensor((*i)->get_sensor_id()))
839 if(end!=blocks.begin() && end!=cur_blocks_end)
840 // Free blocks up to the last inactive sensor
841 release_blocks(blocks.begin(), end);
845 void Train::turnout_path_changed(Track &track)
847 for(list<BlockIter>::iterator i=blocks.begin(); i!=blocks.end(); ++i)
848 if((*i)->get_turnout_id()==track.get_turnout_id() && !reserving)
849 check_turnout_paths(false);
852 void Train::halt_event(bool h)
855 accurate_position = false;
858 void Train::block_reserved(const Block &block, const Train *train)
860 if(&block==pending_block && !train && !reserving)
864 void Train::reserve_more()
866 if(!active || blocks.empty() || end_of_route)
869 BlockIter start = blocks.back();
874 // See how many sensor blocks and how much track we already have
877 for(BlockList::const_iterator i=cur_blocks_end; i!=blocks.end(); ++i)
879 if((*i)->get_sensor_id())
882 dist += (*i)->get_path_length(i->entry());
885 list<RouteRef>::iterator cur_route = routes.begin();
886 advance_route(cur_route, *start.track_iter());
888 float approach_margin = 50*layout.get_catalogue().get_scale();
889 float min_dist = controller->get_braking_distance()*1.3+approach_margin*2;
891 BlockIter block = start;
892 list<BlockIter>::iterator good_end = blocks.end();
893 Track *divert_track = 0;
894 bool try_divert = false;
895 Train *blocking_train = 0;
896 BlockList contested_blocks;
898 SetFlag setf(reserving);
902 BlockIter last = block;
903 block = block.next(cur_route!=routes.end() ? cur_route->route : 0);
904 if(!block || block->get_endpoints().size()<2)
908 good_end = blocks.end();
914 TrackIter track = block.track_iter();
916 if(cur_route!=routes.end())
918 if(!advance_route(cur_route, *track))
920 // Keep the blocks if we arrived at the end of the route
923 good_end = blocks.end();
930 if(block->get_turnout_id() && !last->get_turnout_id())
932 /* We can keep the blocks if we arrive at a turnout from a non-turnout
933 block. Having a turnout block as our last reserved block is not good
934 as it would limit our diversion possibilities for little benefit. */
935 good_end = blocks.end();
936 if(nsens>=3 && dist>=min_dist)
942 if(block->get_train()!=blocking_train)
944 if(blocking_train->free_block(*contested_blocks.back()))
946 // Roll back and start actually reserving the blocks
947 block = blocks.back();
948 cur_route = routes.begin();
949 advance_route(cur_route, *block.track_iter().track());
950 if(blocking_train->get_priority()==priority)
951 blocking_train->yield_to(*this);
957 yield_to(*blocking_train);
958 pending_block = contested_blocks.front().block();
959 try_divert = divert_track;
965 contested_blocks.push_back(block);
970 bool reserved = block->reserve(this);
973 /* We've found another train. If it wants to exit the block from the
974 same endpoint we're trying to enter from or the other way around,
975 treat it as coming towards us. Otherwise treat it as going in the
977 Train *other_train = block->get_train();
978 int other_entry = other_train->get_entry_to_block(*block);
980 throw logic_error("block reservation inconsistency");
982 unsigned exit = block.reverse().entry();
983 unsigned other_exit = BlockIter(block.block(), other_entry).reverse().entry();
984 bool entry_conflict = (block.entry()==other_exit);
985 bool exit_conflict = (exit==static_cast<unsigned>(other_entry));
986 if(!entry_conflict && !last->get_turnout_id())
988 /* The other train is not coming to the blocks we're holding, so we
990 good_end = blocks.end();
992 if(static_cast<unsigned>(other_entry)==block.entry())
993 preceding_train = other_train;
996 int other_prio = other_train->get_priority();
998 if(!entry_conflict && !exit_conflict && other_prio<priority)
1000 /* Ask a lesser priority train going to the same direction to free
1002 if(other_train->free_block(*block))
1003 reserved = block->reserve(this);
1005 else if(other_train!=yielding_to && (other_prio<priority || (other_prio==priority && entry_conflict)))
1007 /* A lesser priority train is coming at us, we must ask it to free
1008 enough blocks to get clear of it to avoid a potential deadlock */
1009 blocking_train = other_train;
1010 contested_blocks.clear();
1011 contested_blocks.push_back(block);
1014 else if(divert_track && (entry_conflict || exit_conflict || !other_train->is_active()))
1015 // We are blocked, but there's a diversion possibility
1020 pending_block = &*block;
1025 if(block->get_turnout_id())
1027 const TrackType::Endpoint &track_ep = track.endpoint();
1028 bool multiple_paths = (track_ep.paths&(track_ep.paths-1));
1030 if(multiple_paths && cur_route!=routes.end() && cur_route->diversion!=block->get_turnout_id())
1031 /* There's multiple paths to be taken and we are on a route - take
1032 note of the diversion possibility */
1033 divert_track = &*track;
1036 if(!contested_blocks.empty() && contested_blocks.front()==block)
1037 contested_blocks.pop_front();
1039 blocks.push_back(block);
1041 if(cur_blocks_end==blocks.end())
1043 if(clear_blocks_end==blocks.end())
1045 if(good_end==blocks.end())
1048 if(block->get_sensor_id())
1051 dist += block->get_path_length(block.entry());
1054 // Unreserve blocks that were not good
1055 release_blocks(good_end, blocks.end());
1057 if(blocks.back()!=start)
1058 // We got some new blocks, so no longer need to yield
1061 check_turnout_paths(true);
1063 // Make any sensorless blocks at the beginning immediately current
1064 while(cur_blocks_end!=clear_blocks_end && !(*cur_blocks_end)->get_sensor_id())
1067 if(try_divert && divert(*divert_track))
1071 void Train::check_turnout_paths(bool set)
1073 if(clear_blocks_end==blocks.end())
1076 for(list<BlockIter>::iterator i=clear_blocks_end; i!=blocks.end(); ++i)
1078 if((*i)->get_turnout_id())
1080 TrackIter track = i->track_iter();
1081 const TrackType::Endpoint &track_ep = track.endpoint();
1084 list<BlockIter>::iterator j = i;
1085 if(++j!=blocks.end())
1087 TrackIter rev = j->track_iter().flip();
1088 unsigned mask = rev.endpoint().paths&track_ep.paths;
1089 for(path=0; mask>1; mask>>=1, ++path) ;
1094 if(path!=track->get_active_path())
1097 track->set_active_path(path);
1099 /* Check again, in case the driver was able to service the request
1101 if(!set || path!=track->get_active_path())
1106 if(i==clear_blocks_end)
1111 float Train::get_reserved_distance_until(const Block *until_block, bool back) const
1116 Vehicle &veh = *(reverse!=back ? vehicles.back() : vehicles.front());
1117 const VehicleType &vtype = veh.get_type();
1119 TrackIter track(veh.get_track(), veh.get_entry());
1120 if(!track) // XXX Probably unnecessary
1123 BlockList::const_iterator block = blocks.begin();
1124 while(block!=clear_blocks_end && !(*block)->has_track(*track))
1126 if(block==clear_blocks_end || &**block==until_block)
1129 float result = veh.get_offset();
1131 track = track.reverse();
1133 result = track->get_type().get_path_length(track->get_active_path())-result;
1134 result -= vtype.get_length()/2;
1138 track = track.next();
1142 if(!(*block)->has_track(*track))
1146 if(block==blocks.begin())
1153 if(block==clear_blocks_end)
1157 if(&**block==until_block)
1161 result += track->get_type().get_path_length(track->get_active_path());
1167 void Train::release_blocks()
1169 release_blocks(blocks.begin(), blocks.end());
1172 void Train::release_blocks(BlockList::iterator begin, BlockList::iterator end)
1176 if(begin==cur_blocks_end)
1177 cur_blocks_end = end;
1178 if(begin==clear_blocks_end)
1179 clear_blocks_end = end;
1181 Block &block = **begin;
1182 blocks.erase(begin++);
1185 if(begin==blocks.end())
1186 end_of_route = false;
1190 void Train::reverse_blocks(BlockList &blks) const
1193 for(BlockList::iterator i=blks.begin(); i!=blks.end(); ++i)
1197 bool Train::advance_route(list<RouteRef>::iterator &iter, Track &track)
1199 while(iter!=routes.end() && !iter->route->has_track(track))
1201 if(iter==routes.end())
1204 list<RouteRef>::iterator next = iter;
1206 if(next!=routes.end() && next->diversion && next->route->has_track(track))
1212 Route *Train::create_lead_route(Route *lead, const Route *target)
1216 lead = new Route(layout);
1217 lead->set_name("Lead");
1218 lead->set_temporary(true);
1221 set<Track *> tracks;
1222 for(BlockList::iterator i=blocks.begin(); i!=blocks.end(); ++i)
1224 const set<Track *> &btracks = (*i)->get_tracks();
1225 for(set<Track *>::const_iterator j=btracks.begin(); j!=btracks.end(); ++j)
1226 if(!target || !target->has_track(**j))
1230 lead->add_tracks(tracks);
1235 bool Train::is_valid_diversion(const Route &diversion, const TrackIter &from)
1237 float diversion_len = 0;
1238 TrackLoopIter track1 = from;
1239 while(diversion.has_track(*track1))
1241 unsigned path = diversion.get_path(*track1);
1242 diversion_len += track1->get_type().get_path_length(path);
1244 track1 = track1.next(path);
1246 if(!track1 || track1.looped())
1250 list<RouteRef>::iterator route = routes.begin();
1251 if(!advance_route(route, *from))
1254 float route_len = 0;
1255 TrackLoopIter track2 = from;
1258 unsigned path = route->route->get_path(*track2);
1259 route_len += track2->get_type().get_path_length(path);
1261 bool ok = (track2!=from && diversion.has_track(*track2));
1263 track2 = track2.next(path);
1273 if(!advance_route(route, *track2))
1277 // Must end up at the same place through both routes
1281 return diversion_len<route_len*1.2;
1285 Train::RouteRef::RouteRef(const Route *r, unsigned d):
1291 Train::Loader::Loader(Train &t):
1292 DataFile::ObjectLoader<Train>(t),
1296 add("block", &Loader::block);
1297 add("block_hint", &Loader::block_hint);
1298 add("name", &Loader::name);
1299 add("priority", &Train::priority);
1300 add("quantized_speed", &Loader::quantized_speed);
1301 add("route", &Loader::route);
1302 add("timetable", &Loader::timetable);
1303 add("vehicle", &Loader::vehicle);
1306 void Train::Loader::finish()
1308 if(!obj.blocks.empty())
1310 TrackIter track = obj.blocks.front().track_iter();
1311 float offset = 2*obj.layout.get_catalogue().get_scale();
1312 obj.vehicles.back()->place(*track, track.entry(), offset, Vehicle::BACK_BUFFER);
1316 void Train::Loader::block(unsigned id)
1324 blk = &obj.layout.get_block(id);
1326 catch(const key_error &)
1328 blocks_valid = false;
1334 entry = blk->get_endpoint_by_link(*prev_block);
1339 obj.blocks.push_back(BlockIter(blk, entry));
1341 if(blk->get_sensor_id())
1342 obj.layout.get_driver().set_sensor(blk->get_sensor_id(), true);
1347 void Train::Loader::block_hint(unsigned id)
1351 prev_block = &obj.layout.get_block(id);
1353 catch(const key_error &)
1355 blocks_valid = false;
1359 void Train::Loader::name(const string &n)
1364 void Train::Loader::quantized_speed()
1366 if(obj.speed_quantizer)
1367 load_sub(*obj.speed_quantizer);
1370 void Train::Loader::route(const string &n)
1372 obj.set_route(&obj.layout.get_route(n));
1375 void Train::Loader::timetable()
1377 Timetable *ttbl = new Timetable(obj);
1381 void Train::Loader::vehicle(ArticleNumber art_nr)
1383 const VehicleType &vtype = obj.layout.get_catalogue().get_vehicle(art_nr);
1384 Vehicle *veh = new Vehicle(obj.layout, vtype);
1385 obj.vehicles.back()->attach_back(*veh);
1386 obj.vehicles.push_back(veh);