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 blocks.push_back(BlockIter(&block, entry));
434 if(!block.reserve(this))
442 TrackIter track = BlockIter(&block, entry).reverse().track_iter();
443 vehicles.front()->place(*track, track.entry(), 0, Vehicle::FRONT_BUFFER);
447 const Block::Endpoint &bep = block.get_endpoint(entry);
448 vehicles.back()->place(*bep.track, bep.track_ep, 0, Vehicle::BACK_BUFFER);
452 void Train::unplace()
454 if(controller->get_speed())
455 throw logic_error("moving");
460 accurate_position = false;
462 for(vector<Vehicle *>::iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
466 bool Train::free_block(Block &block)
468 if(get_reserved_distance_until(&block, false)<controller->get_braking_distance()*1.3)
472 for(BlockList::iterator i=cur_blocks_end; i!=blocks.end(); ++i)
474 if(i->block()==&block)
478 release_blocks(i, blocks.end());
481 else if((*i)->get_sensor_id())
488 void Train::free_noncritical_blocks()
493 if(controller->get_speed()==0)
495 release_blocks(cur_blocks_end, blocks.end());
499 float margin = 10*layout.get_catalogue().get_scale();
500 float min_dist = controller->get_braking_distance()*1.3+margin;
502 Vehicle &veh = *(reverse ? vehicles.back() : vehicles.front());
504 TrackIter track(veh.get_track(), veh.get_entry());
505 BlockList::iterator block = blocks.begin();
507 while(block!=blocks.end() && !(*block)->has_track(*track))
510 if(block==cur_blocks_end)
514 float dist = veh.get_offset();
518 dist = track->get_type().get_path_length(track->get_active_path())-dist;
519 dist -= veh.get_type().get_length()/2;
524 track = track.next();
526 if(!(*block)->has_track(*track))
529 if(block==cur_blocks_end)
531 if(block==blocks.end())
534 if(dist>min_dist && nsens>0)
536 release_blocks(block, blocks.end());
540 if(in_rsv && (*block)->get_sensor_id())
544 dist += track->get_type().get_path_length(track->get_active_path());
548 int Train::get_entry_to_block(const Block &block) const
550 for(BlockList::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
551 if(i->block()==&block)
556 float Train::get_reserved_distance() const
562 TrackIter next = blocks.back().next().track_iter();
563 if(next && next->get_type().is_turnout())
564 margin = 15*layout.get_catalogue().get_scale();
566 return max(get_reserved_distance_until(0, false)-margin, 0.0f);
569 void Train::tick(const Time::TimeStamp &t, const Time::TimeDelta &dt)
571 if(!active && stop_timeout && t>=stop_timeout)
573 release_blocks(cur_blocks_end, blocks.end());
574 stop_timeout = Time::TimeStamp();
577 Driver &driver = layout.get_driver();
579 for(list<TrainAI *>::iterator i=ais.begin(); i!=ais.end(); ++i)
581 controller->tick(dt);
582 float speed = controller->get_speed();
583 bool moving = speed>0;
585 if(controller->get_reverse()!=reverse)
587 reverse = controller->get_reverse();
589 if(loco_type.get_swap_direction())
591 driver.set_loco_reverse(address, r);
593 release_blocks(cur_blocks_end, blocks.end());
594 reverse_blocks(blocks);
601 unsigned speed_step = speed_quantizer->find_speed_step(speed);
602 if(speed_step!=current_speed_step && !speed_changing && !driver.is_halted() && driver.get_power())
604 speed_changing = true;
605 driver.set_loco_speed(address, speed_step);
610 speed = speed_quantizer->get_speed(current_speed_step);
618 Vehicle &vehicle = *(reverse ? vehicles.back() : vehicles.front());
619 Track *track = vehicle.get_track();
622 for(BlockList::const_iterator i=blocks.begin(); (!ok && i!=cur_blocks_end); ++i)
623 ok = (*i)->has_track(*track);
625 float d = speed*(dt/Time::sec);
628 SetFlag setf(advancing);
629 vehicle.advance(reverse ? -d : d);
631 else if(accurate_position)
634 if(overshoot_dist>40*layout.get_catalogue().get_scale())
636 layout.emergency(name+" has not arrived at sensor");
637 accurate_position = false;
641 else if(end_of_route && cur_blocks_end==blocks.end())
644 signal_arrived.emit();
648 if(!blocks.empty() && !blocks.front()->get_sensor_id())
650 float dist = get_reserved_distance_until(&*blocks.front(), true);
652 if(dist>10*layout.get_catalogue().get_scale())
654 Block &block = *blocks.front();
661 void Train::save(list<DataFile::Statement> &st) const
663 st.push_back((DataFile::Statement("name"), name));
665 st.push_back((DataFile::Statement("priority"), priority));
667 for(vector<Vehicle *>::const_iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
668 if(i!=vehicles.begin())
669 st.push_back((DataFile::Statement("vehicle"), (*i)->get_type().get_article_number()));
673 DataFile::Statement ss("quantized_speed");
674 speed_quantizer->save(ss.sub);
678 if(!blocks.empty() && cur_blocks_end!=blocks.begin())
680 BlockList blks(blocks.begin(), BlockList::const_iterator(cur_blocks_end));
682 reverse_blocks(blks);
684 BlockIter prev = blks.front().flip();
685 st.push_back((DataFile::Statement("block_hint"), prev->get_id()));
687 for(BlockList::const_iterator i=blks.begin(); i!=blks.end(); ++i)
688 st.push_back((DataFile::Statement("block"), (*i)->get_id()));
693 list<RouteRef>::const_iterator i = routes.begin();
694 for(; (i!=routes.end() && i->route->is_temporary()); ++i) ;
696 st.push_back((DataFile::Statement("route"), i->route->get_name()));
699 // XXX Need more generic way of saving AI state
700 for(list<TrainAI *>::const_iterator i=ais.begin(); i!=ais.end(); ++i)
701 if(Timetable *timetable = dynamic_cast<Timetable *>(*i))
703 DataFile::Statement ss("timetable");
704 timetable->save(ss.sub);
709 void Train::control_changed(const Controller::Control &ctrl)
711 signal_control_changed.emit(ctrl.name, ctrl.value);
714 void Train::loco_speed_event(unsigned addr, unsigned speed, bool rev)
718 current_speed_step = speed;
720 if(loco_type.get_swap_direction())
723 layout.get_driver().set_loco_reverse(address, r);
724 speed_changing = false;
729 void Train::loco_func_event(unsigned addr, unsigned func, bool state)
734 functions |= 1<<func;
736 functions &= ~(1<<func);
738 signal_function_changed.emit(func, state);
742 void Train::block_state_changed(Block &block, Block::State state)
744 if(state==Block::MAYBE_ACTIVE)
746 // Find the first sensor block from our reserved blocks that isn't this sensor
747 BlockList::iterator end;
749 for(end=cur_blocks_end; end!=blocks.end(); ++end)
750 if((*end)->get_sensor_id())
767 // Compute speed and update related state
768 float travel_time_secs = (Time::now()-last_entry_time)/Time::sec;
770 if(pure_speed && speed_quantizer && current_speed_step>0 && travel_time_secs>=2)
771 speed_quantizer->learn(current_speed_step, travel_dist/travel_time_secs, travel_time_secs);
774 for(BlockList::iterator j=cur_blocks_end; j!=end; ++j)
776 travel_dist += (*j)->get_path_length(j->entry());
778 if(&**j==&block && !advancing)
780 TrackIter track = j->track_iter();
783 track = track.flip();
784 vehicles.back()->place(*track, track.entry(), 0, Vehicle::BACK_AXLE);
787 vehicles.front()->place(*track, track.entry(), 0, Vehicle::FRONT_AXLE);
790 last_entry_time = Time::now();
792 accurate_position = true;
795 // Check if we've reached the next route
798 const Route &route = *(++routes.begin())->route;
799 for(BlockList::iterator j=cur_blocks_end; j!=end; ++j)
800 if(route.has_track(*j->track_iter()))
804 signal_route_changed.emit(routes.front().route);
809 // Move blocks up to the next sensor to our current blocks
810 for(BlockList::iterator j=cur_blocks_end; j!=end; ++j)
811 signal_advanced.emit(**j);
812 cur_blocks_end = end;
814 // Try to get more blocks if we're moving
819 layout.emergency("Sensor for "+name+" triggered out of order");
821 else if(state==Block::INACTIVE)
823 const Vehicle &veh = *(reverse ? vehicles.front() : vehicles.back());
825 // Find the first sensor in our current blocks that's still active
826 BlockList::iterator end = blocks.begin();
827 for(BlockList::iterator i=blocks.begin(); i!=cur_blocks_end; ++i)
829 if((*i)->has_track(*veh.get_track()))
831 if((*i)->get_sensor_id())
833 if(layout.get_driver().get_sensor((*i)->get_sensor_id()))
843 if(end!=blocks.begin() && end!=cur_blocks_end)
844 // Free blocks up to the last inactive sensor
845 release_blocks(blocks.begin(), end);
849 void Train::turnout_path_changed(Track &track)
851 for(list<BlockIter>::iterator i=blocks.begin(); i!=blocks.end(); ++i)
852 if((*i)->get_turnout_id()==track.get_turnout_id() && !reserving)
853 check_turnout_paths(false);
856 void Train::halt_event(bool h)
859 accurate_position = false;
862 void Train::block_reserved(const Block &block, const Train *train)
864 if(&block==pending_block && !train && !reserving)
868 void Train::reserve_more()
870 if(!active || blocks.empty() || end_of_route)
873 BlockIter start = blocks.back();
878 // See how many sensor blocks and how much track we already have
881 for(BlockList::const_iterator i=cur_blocks_end; i!=blocks.end(); ++i)
883 if((*i)->get_sensor_id())
886 dist += (*i)->get_path_length(i->entry());
889 list<RouteRef>::iterator cur_route = routes.begin();
890 advance_route(cur_route, *start.track_iter());
892 float approach_margin = 50*layout.get_catalogue().get_scale();
893 float min_dist = controller->get_braking_distance()*1.3+approach_margin*2;
895 BlockIter block = start;
896 list<BlockIter>::iterator good_end = blocks.end();
897 Track *divert_track = 0;
898 bool try_divert = false;
899 Train *blocking_train = 0;
900 BlockList contested_blocks;
902 SetFlag setf(reserving);
906 BlockIter last = block;
907 block = block.next(cur_route!=routes.end() ? cur_route->route : 0);
908 if(!block || block->get_endpoints().size()<2)
912 good_end = blocks.end();
918 TrackIter track = block.track_iter();
920 if(cur_route!=routes.end())
922 if(!advance_route(cur_route, *track))
924 // Keep the blocks if we arrived at the end of the route
927 good_end = blocks.end();
934 if(block->get_turnout_id() && !last->get_turnout_id())
936 /* We can keep the blocks if we arrive at a turnout from a non-turnout
937 block. Having a turnout block as our last reserved block is not good
938 as it would limit our diversion possibilities for little benefit. */
939 good_end = blocks.end();
940 if(nsens>=3 && dist>=min_dist)
946 if(block->get_train()!=blocking_train)
948 if(blocking_train->free_block(*contested_blocks.back()))
950 // Roll back and start actually reserving the blocks
951 block = blocks.back();
952 cur_route = routes.begin();
953 advance_route(cur_route, *block.track_iter().track());
954 if(blocking_train->get_priority()==priority)
955 blocking_train->yield_to(*this);
961 yield_to(*blocking_train);
962 pending_block = contested_blocks.front().block();
963 try_divert = divert_track;
969 contested_blocks.push_back(block);
974 blocks.push_back(block);
975 bool reserved = block->reserve(this);
979 /* We've found another train. If it wants to exit the block from the
980 same endpoint we're trying to enter from or the other way around,
981 treat it as coming towards us. Otherwise treat it as going in the
983 Train *other_train = block->get_train();
984 int other_entry = other_train->get_entry_to_block(*block);
986 throw logic_error("block reservation inconsistency");
988 unsigned exit = block.reverse().entry();
989 unsigned other_exit = BlockIter(block.block(), other_entry).reverse().entry();
990 bool entry_conflict = (block.entry()==other_exit);
991 bool exit_conflict = (exit==static_cast<unsigned>(other_entry));
992 if(!entry_conflict && !last->get_turnout_id())
994 /* The other train is not coming to the blocks we're holding, so we
996 good_end = blocks.end();
998 if(static_cast<unsigned>(other_entry)==block.entry())
999 preceding_train = other_train;
1002 int other_prio = other_train->get_priority();
1004 if(!entry_conflict && !exit_conflict && other_prio<priority)
1006 /* Ask a lesser priority train going to the same direction to free
1008 if(other_train->free_block(*block))
1010 blocks.push_back(block);
1011 if(!(reserved = block->reserve(this)))
1015 else if(other_train!=yielding_to && (other_prio<priority || (other_prio==priority && entry_conflict)))
1017 /* A lesser priority train is coming at us, we must ask it to free
1018 enough blocks to get clear of it to avoid a potential deadlock */
1019 blocking_train = other_train;
1020 contested_blocks.clear();
1021 contested_blocks.push_back(block);
1024 else if(divert_track && (entry_conflict || exit_conflict || !other_train->is_active()))
1025 // We are blocked, but there's a diversion possibility
1030 pending_block = &*block;
1035 if(block->get_turnout_id())
1037 const TrackType::Endpoint &track_ep = track.endpoint();
1038 bool multiple_paths = (track_ep.paths&(track_ep.paths-1));
1040 if(multiple_paths && cur_route!=routes.end() && cur_route->diversion!=block->get_turnout_id())
1041 /* There's multiple paths to be taken and we are on a route - take
1042 note of the diversion possibility */
1043 divert_track = &*track;
1046 if(!contested_blocks.empty() && contested_blocks.front()==block)
1047 contested_blocks.pop_front();
1049 if(cur_blocks_end==blocks.end())
1051 if(clear_blocks_end==blocks.end())
1053 if(good_end==blocks.end())
1056 if(block->get_sensor_id())
1059 dist += block->get_path_length(block.entry());
1062 // Unreserve blocks that were not good
1063 release_blocks(good_end, blocks.end());
1065 if(blocks.back()!=start)
1066 // We got some new blocks, so no longer need to yield
1069 check_turnout_paths(true);
1071 // Make any sensorless blocks at the beginning immediately current
1072 while(cur_blocks_end!=clear_blocks_end && !(*cur_blocks_end)->get_sensor_id())
1075 if(try_divert && divert(*divert_track))
1079 void Train::check_turnout_paths(bool set)
1081 if(clear_blocks_end==blocks.end())
1084 for(list<BlockIter>::iterator i=clear_blocks_end; i!=blocks.end(); ++i)
1086 if((*i)->get_turnout_id())
1088 TrackIter track = i->track_iter();
1089 const TrackType::Endpoint &track_ep = track.endpoint();
1092 list<BlockIter>::iterator j = i;
1093 if(++j!=blocks.end())
1095 TrackIter rev = j->track_iter().flip();
1096 unsigned mask = rev.endpoint().paths&track_ep.paths;
1097 for(path=0; mask>1; mask>>=1, ++path) ;
1102 if(path!=track->get_active_path())
1105 track->set_active_path(path);
1107 /* Check again, in case the driver was able to service the request
1109 if(!set || path!=track->get_active_path())
1114 if(i==clear_blocks_end)
1116 if(i==cur_blocks_end && !(*i)->get_sensor_id())
1121 float Train::get_reserved_distance_until(const Block *until_block, bool back) const
1126 Vehicle &veh = *(reverse!=back ? vehicles.back() : vehicles.front());
1127 const VehicleType &vtype = veh.get_type();
1129 TrackIter track(veh.get_track(), veh.get_entry());
1130 if(!track) // XXX Probably unnecessary
1133 BlockList::const_iterator block = blocks.begin();
1134 while(block!=clear_blocks_end && !(*block)->has_track(*track))
1136 if(block==clear_blocks_end || &**block==until_block)
1139 float result = veh.get_offset();
1141 track = track.reverse();
1143 result = track->get_type().get_path_length(track->get_active_path())-result;
1144 result -= vtype.get_length()/2;
1148 track = track.next();
1152 if(!(*block)->has_track(*track))
1156 if(block==blocks.begin())
1163 if(block==clear_blocks_end)
1167 if(&**block==until_block)
1171 result += track->get_type().get_path_length(track->get_active_path());
1177 void Train::release_blocks()
1179 release_blocks(blocks.begin(), blocks.end());
1182 void Train::release_blocks(BlockList::iterator begin, BlockList::iterator end)
1186 if(begin==cur_blocks_end)
1187 cur_blocks_end = end;
1188 if(begin==clear_blocks_end)
1189 clear_blocks_end = end;
1191 Block &block = **begin;
1192 blocks.erase(begin++);
1195 if(begin==blocks.end())
1196 end_of_route = false;
1200 void Train::reverse_blocks(BlockList &blks) const
1203 for(BlockList::iterator i=blks.begin(); i!=blks.end(); ++i)
1207 bool Train::advance_route(list<RouteRef>::iterator &iter, Track &track)
1209 while(iter!=routes.end() && !iter->route->has_track(track))
1211 if(iter==routes.end())
1214 list<RouteRef>::iterator next = iter;
1216 if(next!=routes.end() && next->diversion && next->route->has_track(track))
1222 Route *Train::create_lead_route(Route *lead, const Route *target)
1226 lead = new Route(layout);
1227 lead->set_name("Lead");
1228 lead->set_temporary(true);
1231 set<Track *> tracks;
1232 for(BlockList::iterator i=blocks.begin(); i!=blocks.end(); ++i)
1234 const set<Track *> &btracks = (*i)->get_tracks();
1235 for(set<Track *>::const_iterator j=btracks.begin(); j!=btracks.end(); ++j)
1236 if(!target || !target->has_track(**j))
1240 lead->add_tracks(tracks);
1245 bool Train::is_valid_diversion(const Route &diversion, const TrackIter &from)
1247 float diversion_len = 0;
1248 TrackLoopIter track1 = from;
1249 while(diversion.has_track(*track1))
1251 unsigned path = diversion.get_path(*track1);
1252 diversion_len += track1->get_type().get_path_length(path);
1254 track1 = track1.next(path);
1256 if(!track1 || track1.looped())
1260 list<RouteRef>::iterator route = routes.begin();
1261 if(!advance_route(route, *from))
1264 float route_len = 0;
1265 TrackLoopIter track2 = from;
1268 unsigned path = route->route->get_path(*track2);
1269 route_len += track2->get_type().get_path_length(path);
1271 bool ok = (track2!=from && diversion.has_track(*track2));
1273 track2 = track2.next(path);
1283 if(!advance_route(route, *track2))
1287 // Must end up at the same place through both routes
1291 return diversion_len<route_len*1.2;
1295 Train::RouteRef::RouteRef(const Route *r, unsigned d):
1301 Train::Loader::Loader(Train &t):
1302 DataFile::ObjectLoader<Train>(t),
1306 add("block", &Loader::block);
1307 add("block_hint", &Loader::block_hint);
1308 add("name", &Loader::name);
1309 add("priority", &Train::priority);
1310 add("quantized_speed", &Loader::quantized_speed);
1311 add("route", &Loader::route);
1312 add("timetable", &Loader::timetable);
1313 add("vehicle", &Loader::vehicle);
1316 void Train::Loader::finish()
1318 if(!obj.blocks.empty())
1320 TrackIter track = obj.blocks.front().track_iter();
1321 float offset = 2*obj.layout.get_catalogue().get_scale();
1322 obj.vehicles.back()->place(*track, track.entry(), offset, Vehicle::BACK_BUFFER);
1326 void Train::Loader::block(unsigned id)
1334 blk = &obj.layout.get_block(id);
1336 catch(const key_error &)
1338 blocks_valid = false;
1344 entry = blk->get_endpoint_by_link(*prev_block);
1348 obj.blocks.push_back(BlockIter(blk, entry));
1351 if(blk->get_sensor_id())
1352 obj.layout.get_driver().set_sensor(blk->get_sensor_id(), true);
1357 void Train::Loader::block_hint(unsigned id)
1361 prev_block = &obj.layout.get_block(id);
1363 catch(const key_error &)
1365 blocks_valid = false;
1369 void Train::Loader::name(const string &n)
1374 void Train::Loader::quantized_speed()
1376 if(obj.speed_quantizer)
1377 load_sub(*obj.speed_quantizer);
1380 void Train::Loader::route(const string &n)
1382 obj.set_route(&obj.layout.get_route(n));
1385 void Train::Loader::timetable()
1387 Timetable *ttbl = new Timetable(obj);
1391 void Train::Loader::vehicle(ArticleNumber art_nr)
1393 const VehicleType &vtype = obj.layout.get_catalogue().get_vehicle(art_nr);
1394 Vehicle *veh = new Vehicle(obj.layout, vtype);
1395 obj.vehicles.back()->attach_back(*veh);
1396 obj.vehicles.push_back(veh);