3 This file is part of R²C²
4 Copyright © 2006-2011 Mikkosoft Productions, Mikko Rasa
5 Distributed under the GPL
10 #include <msp/strings/formatter.h>
11 #include <msp/time/units.h>
12 #include <msp/time/utils.h>
13 #include "aicontrol.h"
14 #include "catalogue.h"
18 #include "simplecontroller.h"
19 #include "speedquantizer.h"
20 #include "timetable.h"
21 #include "trackiter.h"
22 #include "tracktype.h"
25 #include "vehicletype.h"
37 SetFlag(bool &f): flag(f) { flag = true; }
38 ~SetFlag() { flag = false; }
46 Train::Train(Layout &l, const VehicleType &t, unsigned a, const string &p):
54 cur_blocks_end(blocks.end()),
55 clear_blocks_end(blocks.end()),
59 controller(new SimpleController),
61 current_speed_step(0),
62 speed_changing(false),
69 accurate_position(false),
72 if(!loco_type.is_locomotive())
73 throw InvalidParameterValue("Initial vehicle must be a locomotive");
75 unsigned speed_steps = layout.get_driver().get_protocol_speed_steps(protocol);
77 speed_quantizer = new SpeedQuantizer(speed_steps);
79 vehicles.push_back(new Vehicle(layout, loco_type));
81 layout.add_train(*this);
83 layout.get_driver().add_loco(address, protocol, loco_type);
84 layout.get_driver().signal_loco_speed.connect(sigc::mem_fun(this, &Train::loco_speed_event));
85 layout.get_driver().signal_loco_function.connect(sigc::mem_fun(this, &Train::loco_func_event));
87 layout.signal_block_reserved.connect(sigc::mem_fun(this, &Train::block_reserved));
88 layout.signal_block_state_changed.connect(sigc::mem_fun(this, &Train::block_state_changed));
90 layout.get_driver().signal_halt.connect(sigc::mem_fun(this, &Train::halt_event));
92 const set<Track *> &tracks = layout.get_tracks();
93 for(set<Track *>::const_iterator i=tracks.begin(); i!=tracks.end(); ++i)
94 if((*i)->get_turnout_id())
95 (*i)->signal_path_changed.connect(sigc::hide(sigc::bind(sigc::mem_fun(this, &Train::turnout_path_changed), sigc::ref(**i))));
97 controller->signal_control_changed.connect(sigc::mem_fun(this, &Train::control_changed));
103 for(vector<Vehicle *>::iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
105 layout.remove_train(*this);
108 void Train::set_name(const string &n)
112 signal_name_changed.emit(name);
115 void Train::set_priority(int p)
120 void Train::yield_to(const Train &t)
125 void Train::add_vehicle(const VehicleType &vt)
127 Vehicle *veh = new Vehicle(layout, vt);
128 vehicles.back()->attach_back(*veh);
129 vehicles.push_back(veh);
132 void Train::remove_vehicle(unsigned i)
134 if(i>=vehicles.size())
135 throw InvalidParameterValue("Vehicle index out of range");
137 throw InvalidParameterValue("Can't remove the locomotive");
139 vehicles.erase(vehicles.begin()+i);
140 if(i<vehicles.size())
141 vehicles[i-1]->attach_back(*vehicles[i]);
144 unsigned Train::get_n_vehicles() const
146 return vehicles.size();
149 Vehicle &Train::get_vehicle(unsigned i)
151 if(i>=vehicles.size())
152 throw InvalidParameterValue("Vehicle index out of range");
156 const Vehicle &Train::get_vehicle(unsigned i) const
158 if(i>=vehicles.size())
159 throw InvalidParameterValue("Vehicle index out of range");
163 void Train::set_control(const string &n, float v)
165 controller->set_control(n, v);
168 void Train::set_active(bool a)
172 if(!a && controller->get_speed())
173 throw InvalidState("Can't deactivate while moving");
178 stop_timeout = Time::TimeStamp();
182 stop_timeout = Time::now()+2*Time::sec;
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 float Train::get_quantized_speed() const
205 return speed_quantizer->quantize_speed(controller->get_speed());
207 return controller->get_speed();
210 bool Train::get_function(unsigned func) const
212 return (functions>>func)&1;
215 void Train::add_ai(TrainAI &ai)
218 ai.signal_event.connect(sigc::bind<0>(signal_ai_event, sigc::ref(ai)));
221 void Train::remove_ai(TrainAI &ai)
223 list<TrainAI *>::iterator i = find(ais.begin(), ais.end(), &ai);
228 TrainAI *Train::get_tagged_ai(const string &tag) const
230 for(list<TrainAI *>::const_iterator i=ais.begin(); i!=ais.end(); ++i)
231 if((*i)->get_tag()==tag)
237 void Train::ai_message(const TrainAI::Message &msg)
239 for(list<TrainAI *>::iterator i=ais.begin(); i!=ais.end(); ++i)
243 bool Train::set_route(const Route *r)
245 free_noncritical_blocks();
248 if(r && !blocks.empty())
250 TrackIter first = blocks.front().track_iter();
251 TrackIter next = blocks.back().next().track_iter();
252 if(!r->has_track(*next))
254 lead = Route::find(next, *r);
257 create_lead_route(lead, lead);
258 routes.push_front(lead);
260 else if(!r->has_track(*first))
261 lead = create_lead_route(0, r);
266 routes.push_back(lead);
269 end_of_route = false;
273 signal_route_changed.emit(get_route());
278 bool Train::go_to(Track &to)
280 for(BlockList::const_iterator i=blocks.begin(); i!=cur_blocks_end; ++i)
281 if((*i)->has_track(to))
283 signal_arrived.emit();
287 free_noncritical_blocks();
289 TrackIter next = blocks.back().next().track_iter();
291 Route *route = Route::find(next, to);
294 create_lead_route(route, route);
295 return set_route(route);
298 bool Train::go_to(const Zone &to)
301 for(BlockList::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
302 tracks.insert((*i)->get_tracks().begin(), (*i)->get_tracks().end());
304 const Zone::TrackSet &ztracks = to.get_tracks();
305 unsigned union_size = 0;
306 for(Zone::TrackSet::const_iterator i=ztracks.begin(); i!=ztracks.end(); ++i)
307 union_size += tracks.count(*i);
309 if(union_size==tracks.size() || union_size==ztracks.size())
311 signal_arrived.emit();
315 free_noncritical_blocks();
317 TrackIter next = blocks.back().next().track_iter();
319 Route *route = Route::find(next, to);
322 create_lead_route(route, route);
323 route->add_tracks(ztracks);
324 return set_route(route);
327 bool Train::divert(Track &from)
329 if(!from.get_turnout_id())
330 throw InvalidParameterValue("Can't divert from a non-turnout");
336 list<RouteRef>::iterator route = routes.begin();
338 // Follow our routes to find out where we're entering the turnout
339 for(TrackLoopIter track = blocks.front().track_iter();;)
341 if(!advance_route(route, *track))
346 Block &block = track->get_block();
347 if(block.get_train()==this && !free_block(block))
350 int route_path = route->route->get_turnout(from.get_turnout_id());
352 // Check that more than one path is available
353 unsigned ep_paths = track.endpoint().paths;
354 if(!(ep_paths&(ep_paths-1)))
357 // Choose some other path
358 for(int i=0; ep_paths>>i; ++i)
359 if((ep_paths&(1<<i)) && i!=route_path)
365 entry = track.entry();
369 track = track.next(route->route->get_path(*track));
371 if(!track || track.looped())
375 TrackIter track = TrackIter(&from, entry).next(path);
380 for(list<RouteRef>::iterator i=routes.begin(); i!=routes.end(); ++i)
381 tracks.insert(i->route->get_tracks().begin(), i->route->get_tracks().end());
382 RefPtr<Route> diversion = Route::find(track, tracks);
386 diversion->set_name("Diversion");
387 diversion->add_track(from);
388 diversion->set_turnout(from.get_turnout_id(), path);
390 if(!is_valid_diversion(*diversion, TrackIter(&from, entry)))
393 // Follow the diversion route until we get back to the original route
394 list<RouteRef>::iterator end = routes.end();
397 for(list<RouteRef>::iterator i=route; (end==routes.end() && i!=routes.end()); ++i)
398 if(i->route->has_track(*track))
401 if(end!=routes.end())
403 else if(!diversion->has_track(*track))
404 throw LogicError("Pathfinder returned a bad route");
406 track = track.next(diversion->get_path(*track));
410 // We are rejoining the same route we diverted from, duplicate it
411 routes.insert(end, *route);
415 routes.erase(route, end);
417 routes.insert(end, RouteRef(diversion.release(), from.get_turnout_id()));
422 const Route *Train::get_route() const
426 return routes.front().route;
429 void Train::place(Block &block, unsigned entry)
431 if(controller->get_speed())
432 throw InvalidState("Must be stopped before placing");
437 accurate_position = false;
439 if(!block.reserve(this))
442 blocks.push_back(BlockIter(&block, entry));
445 TrackIter track = BlockIter(&block, entry).reverse().track_iter();
446 vehicles.front()->place(*track, track.entry(), 0, Vehicle::FRONT_BUFFER);
450 const Block::Endpoint &bep = block.get_endpoint(entry);
451 vehicles.back()->place(*bep.track, bep.track_ep, 0, Vehicle::BACK_BUFFER);
455 void Train::unplace()
457 if(controller->get_speed())
458 throw InvalidState("Must be stopped before unplacing");
463 accurate_position = false;
465 for(vector<Vehicle *>::iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
469 bool Train::free_block(Block &block)
471 if(get_reserved_distance_until(&block, false)<controller->get_braking_distance()*1.3)
475 for(BlockList::iterator i=cur_blocks_end; i!=blocks.end(); ++i)
477 if(i->block()==&block)
481 release_blocks(i, blocks.end());
484 else if((*i)->get_sensor_id())
491 void Train::free_noncritical_blocks()
496 if(controller->get_speed()==0)
498 release_blocks(cur_blocks_end, blocks.end());
502 float margin = 10*layout.get_catalogue().get_scale();
503 float min_dist = controller->get_braking_distance()*1.3+margin;
505 Vehicle &veh = *(reverse ? vehicles.back() : vehicles.front());
507 TrackIter track(veh.get_track(), veh.get_entry());
508 BlockList::iterator block = blocks.begin();
510 while(block!=blocks.end() && !(*block)->has_track(*track))
513 if(block==cur_blocks_end)
517 float dist = veh.get_offset();
521 dist = track->get_type().get_path_length(track->get_active_path())-dist;
522 dist -= veh.get_type().get_length()/2;
527 track = track.next();
529 if(!(*block)->has_track(*track))
532 if(block==cur_blocks_end)
534 if(block==blocks.end())
537 if(dist>min_dist && nsens>0)
539 release_blocks(block, blocks.end());
543 if(in_rsv && (*block)->get_sensor_id())
547 dist += track->get_type().get_path_length(track->get_active_path());
551 int Train::get_entry_to_block(Block &block) const
553 for(BlockList::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
554 if(i->block()==&block)
559 float Train::get_reserved_distance() const
565 TrackIter next = blocks.back().next().track_iter();
566 if(next && next->get_type().is_turnout())
567 margin = 15*layout.get_catalogue().get_scale();
569 return max(get_reserved_distance_until(0, false)-margin, 0.0f);
572 void Train::tick(const Time::TimeStamp &t, const Time::TimeDelta &dt)
574 if(!active && stop_timeout && t>=stop_timeout)
576 release_blocks(cur_blocks_end, blocks.end());
577 stop_timeout = Time::TimeStamp();
580 Driver &driver = layout.get_driver();
582 for(list<TrainAI *>::iterator i=ais.begin(); i!=ais.end(); ++i)
584 controller->tick(dt);
585 float speed = controller->get_speed();
586 bool moving = speed>0;
588 if(controller->get_reverse()!=reverse)
590 reverse = controller->get_reverse();
591 driver.set_loco_reverse(address, reverse);
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 blocks.front()->reserve(0);
660 void Train::save(list<DataFile::Statement> &st) const
662 st.push_back((DataFile::Statement("name"), name));
664 st.push_back((DataFile::Statement("priority"), priority));
666 for(vector<Vehicle *>::const_iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
667 if(i!=vehicles.begin())
668 st.push_back((DataFile::Statement("vehicle"), (*i)->get_type().get_article_number()));
672 DataFile::Statement ss("quantized_speed");
673 speed_quantizer->save(ss.sub);
677 if(!blocks.empty() && cur_blocks_end!=blocks.begin())
679 BlockList blks(blocks.begin(), BlockList::const_iterator(cur_blocks_end));
681 reverse_blocks(blks);
683 BlockIter prev = blks.front().flip();
684 st.push_back((DataFile::Statement("block_hint"), prev->get_id()));
686 for(BlockList::const_iterator i=blks.begin(); i!=blks.end(); ++i)
687 st.push_back((DataFile::Statement("block"), (*i)->get_id()));
692 list<RouteRef>::const_iterator i = routes.begin();
693 for(; (i!=routes.end() && i->route->is_temporary()); ++i) ;
695 st.push_back((DataFile::Statement("route"), i->route->get_name()));
698 // XXX Need more generic way of saving AI state
699 for(list<TrainAI *>::const_iterator i=ais.begin(); i!=ais.end(); ++i)
700 if(Timetable *timetable = dynamic_cast<Timetable *>(*i))
702 DataFile::Statement ss("timetable");
703 timetable->save(ss.sub);
708 void Train::control_changed(const Controller::Control &ctrl)
710 signal_control_changed.emit(ctrl.name, ctrl.value);
713 void Train::loco_speed_event(unsigned addr, unsigned speed, bool rev)
717 current_speed_step = speed;
719 layout.get_driver().set_loco_reverse(address, reverse);
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)
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 LogicError("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::BasicLoader<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 KeyError &)
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 KeyError &)
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);