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();
592 if(loco_type.get_swap_direction())
594 driver.set_loco_reverse(address, r);
596 release_blocks(cur_blocks_end, blocks.end());
597 reverse_blocks(blocks);
604 unsigned speed_step = speed_quantizer->find_speed_step(speed);
605 if(speed_step!=current_speed_step && !speed_changing && !driver.is_halted() && driver.get_power())
607 speed_changing = true;
608 driver.set_loco_speed(address, speed_step);
613 speed = speed_quantizer->get_speed(current_speed_step);
621 Vehicle &vehicle = *(reverse ? vehicles.back() : vehicles.front());
622 Track *track = vehicle.get_track();
625 for(BlockList::const_iterator i=blocks.begin(); (!ok && i!=cur_blocks_end); ++i)
626 ok = (*i)->has_track(*track);
628 float d = speed*(dt/Time::sec);
631 SetFlag setf(advancing);
632 vehicle.advance(reverse ? -d : d);
634 else if(accurate_position)
637 if(overshoot_dist>40*layout.get_catalogue().get_scale())
639 layout.emergency(name+" has not arrived at sensor");
640 accurate_position = false;
644 else if(end_of_route && cur_blocks_end==blocks.end())
647 signal_arrived.emit();
651 if(!blocks.empty() && !blocks.front()->get_sensor_id())
653 float dist = get_reserved_distance_until(&*blocks.front(), true);
655 if(dist>10*layout.get_catalogue().get_scale())
657 blocks.front()->reserve(0);
663 void Train::save(list<DataFile::Statement> &st) const
665 st.push_back((DataFile::Statement("name"), name));
667 st.push_back((DataFile::Statement("priority"), priority));
669 for(vector<Vehicle *>::const_iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
670 if(i!=vehicles.begin())
671 st.push_back((DataFile::Statement("vehicle"), (*i)->get_type().get_article_number()));
675 DataFile::Statement ss("quantized_speed");
676 speed_quantizer->save(ss.sub);
680 if(!blocks.empty() && cur_blocks_end!=blocks.begin())
682 BlockList blks(blocks.begin(), BlockList::const_iterator(cur_blocks_end));
684 reverse_blocks(blks);
686 BlockIter prev = blks.front().flip();
687 st.push_back((DataFile::Statement("block_hint"), prev->get_id()));
689 for(BlockList::const_iterator i=blks.begin(); i!=blks.end(); ++i)
690 st.push_back((DataFile::Statement("block"), (*i)->get_id()));
695 list<RouteRef>::const_iterator i = routes.begin();
696 for(; (i!=routes.end() && i->route->is_temporary()); ++i) ;
698 st.push_back((DataFile::Statement("route"), i->route->get_name()));
701 // XXX Need more generic way of saving AI state
702 for(list<TrainAI *>::const_iterator i=ais.begin(); i!=ais.end(); ++i)
703 if(Timetable *timetable = dynamic_cast<Timetable *>(*i))
705 DataFile::Statement ss("timetable");
706 timetable->save(ss.sub);
711 void Train::control_changed(const Controller::Control &ctrl)
713 signal_control_changed.emit(ctrl.name, ctrl.value);
716 void Train::loco_speed_event(unsigned addr, unsigned speed, bool rev)
720 current_speed_step = speed;
722 if(loco_type.get_swap_direction())
725 layout.get_driver().set_loco_reverse(address, r);
726 speed_changing = false;
731 void Train::loco_func_event(unsigned addr, unsigned func, bool state)
736 functions |= 1<<func;
738 functions &= ~(1<<func);
740 signal_function_changed.emit(func, state);
744 void Train::block_state_changed(Block &block, Block::State state)
746 if(state==Block::MAYBE_ACTIVE)
748 // Find the first sensor block from our reserved blocks that isn't this sensor
749 BlockList::iterator end;
751 for(end=cur_blocks_end; end!=blocks.end(); ++end)
752 if((*end)->get_sensor_id())
769 // Compute speed and update related state
770 float travel_time_secs = (Time::now()-last_entry_time)/Time::sec;
772 if(pure_speed && speed_quantizer && current_speed_step>0 && travel_time_secs>=2)
773 speed_quantizer->learn(current_speed_step, travel_dist/travel_time_secs, travel_time_secs);
776 for(BlockList::iterator j=cur_blocks_end; j!=end; ++j)
778 travel_dist += (*j)->get_path_length(j->entry());
780 if(&**j==&block && !advancing)
782 TrackIter track = j->track_iter();
785 track = track.flip();
786 vehicles.back()->place(*track, track.entry(), 0, Vehicle::BACK_AXLE);
789 vehicles.front()->place(*track, track.entry(), 0, Vehicle::FRONT_AXLE);
792 last_entry_time = Time::now();
794 accurate_position = true;
797 // Check if we've reached the next route
800 const Route &route = *(++routes.begin())->route;
801 for(BlockList::iterator j=cur_blocks_end; j!=end; ++j)
802 if(route.has_track(*j->track_iter()))
806 signal_route_changed.emit(routes.front().route);
811 // Move blocks up to the next sensor to our current blocks
812 for(BlockList::iterator j=cur_blocks_end; j!=end; ++j)
813 signal_advanced.emit(**j);
814 cur_blocks_end = end;
816 // Try to get more blocks if we're moving
821 layout.emergency("Sensor for "+name+" triggered out of order");
823 else if(state==Block::INACTIVE)
825 const Vehicle &veh = *(reverse ? vehicles.front() : vehicles.back());
827 // Find the first sensor in our current blocks that's still active
828 BlockList::iterator end = blocks.begin();
829 for(BlockList::iterator i=blocks.begin(); i!=cur_blocks_end; ++i)
831 if((*i)->has_track(*veh.get_track()))
833 if((*i)->get_sensor_id())
835 if(layout.get_driver().get_sensor((*i)->get_sensor_id()))
845 if(end!=blocks.begin() && end!=cur_blocks_end)
846 // Free blocks up to the last inactive sensor
847 release_blocks(blocks.begin(), end);
851 void Train::turnout_path_changed(Track &track)
853 for(list<BlockIter>::iterator i=blocks.begin(); i!=blocks.end(); ++i)
854 if((*i)->get_turnout_id()==track.get_turnout_id() && !reserving)
855 check_turnout_paths(false);
858 void Train::halt_event(bool h)
861 accurate_position = false;
864 void Train::block_reserved(const Block &block, const Train *train)
866 if(&block==pending_block && !train && !reserving)
870 void Train::reserve_more()
872 if(!active || blocks.empty() || end_of_route)
875 BlockIter start = blocks.back();
880 // See how many sensor blocks and how much track we already have
883 for(BlockList::const_iterator i=cur_blocks_end; i!=blocks.end(); ++i)
885 if((*i)->get_sensor_id())
888 dist += (*i)->get_path_length(i->entry());
891 list<RouteRef>::iterator cur_route = routes.begin();
892 advance_route(cur_route, *start.track_iter());
894 float approach_margin = 50*layout.get_catalogue().get_scale();
895 float min_dist = controller->get_braking_distance()*1.3+approach_margin*2;
897 BlockIter block = start;
898 list<BlockIter>::iterator good_end = blocks.end();
899 Track *divert_track = 0;
900 bool try_divert = false;
901 Train *blocking_train = 0;
902 BlockList contested_blocks;
904 SetFlag setf(reserving);
908 BlockIter last = block;
909 block = block.next(cur_route!=routes.end() ? cur_route->route : 0);
910 if(!block || block->get_endpoints().size()<2)
914 good_end = blocks.end();
920 TrackIter track = block.track_iter();
922 if(cur_route!=routes.end())
924 if(!advance_route(cur_route, *track))
926 // Keep the blocks if we arrived at the end of the route
929 good_end = blocks.end();
936 if(block->get_turnout_id() && !last->get_turnout_id())
938 /* We can keep the blocks if we arrive at a turnout from a non-turnout
939 block. Having a turnout block as our last reserved block is not good
940 as it would limit our diversion possibilities for little benefit. */
941 good_end = blocks.end();
942 if(nsens>=3 && dist>=min_dist)
948 if(block->get_train()!=blocking_train)
950 if(blocking_train->free_block(*contested_blocks.back()))
952 // Roll back and start actually reserving the blocks
953 block = blocks.back();
954 cur_route = routes.begin();
955 advance_route(cur_route, *block.track_iter().track());
956 if(blocking_train->get_priority()==priority)
957 blocking_train->yield_to(*this);
963 yield_to(*blocking_train);
964 pending_block = contested_blocks.front().block();
965 try_divert = divert_track;
971 contested_blocks.push_back(block);
976 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 LogicError("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))
1009 reserved = block->reserve(this);
1011 else if(other_train!=yielding_to && (other_prio<priority || (other_prio==priority && entry_conflict)))
1013 /* A lesser priority train is coming at us, we must ask it to free
1014 enough blocks to get clear of it to avoid a potential deadlock */
1015 blocking_train = other_train;
1016 contested_blocks.clear();
1017 contested_blocks.push_back(block);
1020 else if(divert_track && (entry_conflict || exit_conflict || !other_train->is_active()))
1021 // We are blocked, but there's a diversion possibility
1026 pending_block = &*block;
1031 if(block->get_turnout_id())
1033 const TrackType::Endpoint &track_ep = track.endpoint();
1034 bool multiple_paths = (track_ep.paths&(track_ep.paths-1));
1036 if(multiple_paths && cur_route!=routes.end() && cur_route->diversion!=block->get_turnout_id())
1037 /* There's multiple paths to be taken and we are on a route - take
1038 note of the diversion possibility */
1039 divert_track = &*track;
1042 if(!contested_blocks.empty() && contested_blocks.front()==block)
1043 contested_blocks.pop_front();
1045 blocks.push_back(block);
1047 if(cur_blocks_end==blocks.end())
1049 if(clear_blocks_end==blocks.end())
1051 if(good_end==blocks.end())
1054 if(block->get_sensor_id())
1057 dist += block->get_path_length(block.entry());
1060 // Unreserve blocks that were not good
1061 release_blocks(good_end, blocks.end());
1063 if(blocks.back()!=start)
1064 // We got some new blocks, so no longer need to yield
1067 check_turnout_paths(true);
1069 // Make any sensorless blocks at the beginning immediately current
1070 while(cur_blocks_end!=clear_blocks_end && !(*cur_blocks_end)->get_sensor_id())
1073 if(try_divert && divert(*divert_track))
1077 void Train::check_turnout_paths(bool set)
1079 if(clear_blocks_end==blocks.end())
1082 for(list<BlockIter>::iterator i=clear_blocks_end; i!=blocks.end(); ++i)
1084 if((*i)->get_turnout_id())
1086 TrackIter track = i->track_iter();
1087 const TrackType::Endpoint &track_ep = track.endpoint();
1090 list<BlockIter>::iterator j = i;
1091 if(++j!=blocks.end())
1093 TrackIter rev = j->track_iter().flip();
1094 unsigned mask = rev.endpoint().paths&track_ep.paths;
1095 for(path=0; mask>1; mask>>=1, ++path) ;
1100 if(path!=track->get_active_path())
1103 track->set_active_path(path);
1105 /* Check again, in case the driver was able to service the request
1107 if(!set || path!=track->get_active_path())
1112 if(i==clear_blocks_end)
1117 float Train::get_reserved_distance_until(const Block *until_block, bool back) const
1122 Vehicle &veh = *(reverse!=back ? vehicles.back() : vehicles.front());
1123 const VehicleType &vtype = veh.get_type();
1125 TrackIter track(veh.get_track(), veh.get_entry());
1126 if(!track) // XXX Probably unnecessary
1129 BlockList::const_iterator block = blocks.begin();
1130 while(block!=clear_blocks_end && !(*block)->has_track(*track))
1132 if(block==clear_blocks_end || &**block==until_block)
1135 float result = veh.get_offset();
1137 track = track.reverse();
1139 result = track->get_type().get_path_length(track->get_active_path())-result;
1140 result -= vtype.get_length()/2;
1144 track = track.next();
1148 if(!(*block)->has_track(*track))
1152 if(block==blocks.begin())
1159 if(block==clear_blocks_end)
1163 if(&**block==until_block)
1167 result += track->get_type().get_path_length(track->get_active_path());
1173 void Train::release_blocks()
1175 release_blocks(blocks.begin(), blocks.end());
1178 void Train::release_blocks(BlockList::iterator begin, BlockList::iterator end)
1182 if(begin==cur_blocks_end)
1183 cur_blocks_end = end;
1184 if(begin==clear_blocks_end)
1185 clear_blocks_end = end;
1187 Block &block = **begin;
1188 blocks.erase(begin++);
1191 if(begin==blocks.end())
1192 end_of_route = false;
1196 void Train::reverse_blocks(BlockList &blks) const
1199 for(BlockList::iterator i=blks.begin(); i!=blks.end(); ++i)
1203 bool Train::advance_route(list<RouteRef>::iterator &iter, Track &track)
1205 while(iter!=routes.end() && !iter->route->has_track(track))
1207 if(iter==routes.end())
1210 list<RouteRef>::iterator next = iter;
1212 if(next!=routes.end() && next->diversion && next->route->has_track(track))
1218 Route *Train::create_lead_route(Route *lead, const Route *target)
1222 lead = new Route(layout);
1223 lead->set_name("Lead");
1224 lead->set_temporary(true);
1227 set<Track *> tracks;
1228 for(BlockList::iterator i=blocks.begin(); i!=blocks.end(); ++i)
1230 const set<Track *> &btracks = (*i)->get_tracks();
1231 for(set<Track *>::const_iterator j=btracks.begin(); j!=btracks.end(); ++j)
1232 if(!target || !target->has_track(**j))
1236 lead->add_tracks(tracks);
1241 bool Train::is_valid_diversion(const Route &diversion, const TrackIter &from)
1243 float diversion_len = 0;
1244 TrackLoopIter track1 = from;
1245 while(diversion.has_track(*track1))
1247 unsigned path = diversion.get_path(*track1);
1248 diversion_len += track1->get_type().get_path_length(path);
1250 track1 = track1.next(path);
1252 if(!track1 || track1.looped())
1256 list<RouteRef>::iterator route = routes.begin();
1257 if(!advance_route(route, *from))
1260 float route_len = 0;
1261 TrackLoopIter track2 = from;
1264 unsigned path = route->route->get_path(*track2);
1265 route_len += track2->get_type().get_path_length(path);
1267 bool ok = (track2!=from && diversion.has_track(*track2));
1269 track2 = track2.next(path);
1279 if(!advance_route(route, *track2))
1283 // Must end up at the same place through both routes
1287 return diversion_len<route_len*1.2;
1291 Train::RouteRef::RouteRef(const Route *r, unsigned d):
1297 Train::Loader::Loader(Train &t):
1298 DataFile::BasicLoader<Train>(t),
1302 add("block", &Loader::block);
1303 add("block_hint", &Loader::block_hint);
1304 add("name", &Loader::name);
1305 add("priority", &Train::priority);
1306 add("quantized_speed", &Loader::quantized_speed);
1307 add("route", &Loader::route);
1308 add("timetable", &Loader::timetable);
1309 add("vehicle", &Loader::vehicle);
1312 void Train::Loader::finish()
1314 if(!obj.blocks.empty())
1316 TrackIter track = obj.blocks.front().track_iter();
1317 float offset = 2*obj.layout.get_catalogue().get_scale();
1318 obj.vehicles.back()->place(*track, track.entry(), offset, Vehicle::BACK_BUFFER);
1322 void Train::Loader::block(unsigned id)
1330 blk = &obj.layout.get_block(id);
1332 catch(const KeyError &)
1334 blocks_valid = false;
1340 entry = blk->get_endpoint_by_link(*prev_block);
1345 obj.blocks.push_back(BlockIter(blk, entry));
1347 if(blk->get_sensor_id())
1348 obj.layout.get_driver().set_sensor(blk->get_sensor_id(), true);
1353 void Train::Loader::block_hint(unsigned id)
1357 prev_block = &obj.layout.get_block(id);
1359 catch(const KeyError &)
1361 blocks_valid = false;
1365 void Train::Loader::name(const string &n)
1370 void Train::Loader::quantized_speed()
1372 if(obj.speed_quantizer)
1373 load_sub(*obj.speed_quantizer);
1376 void Train::Loader::route(const string &n)
1378 obj.set_route(&obj.layout.get_route(n));
1381 void Train::Loader::timetable()
1383 Timetable *ttbl = new Timetable(obj);
1387 void Train::Loader::vehicle(ArticleNumber art_nr)
1389 const VehicleType &vtype = obj.layout.get_catalogue().get_vehicle(art_nr);
1390 Vehicle *veh = new Vehicle(obj.layout, vtype);
1391 obj.vehicles.back()->attach_back(*veh);
1392 obj.vehicles.push_back(veh);