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.get_driver().signal_sensor.connect(sigc::mem_fun(this, &Train::sensor_event));
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();
587 if(controller->get_reverse()!=reverse)
589 reverse = controller->get_reverse();
590 driver.set_loco_reverse(address, reverse);
592 release_blocks(cur_blocks_end, blocks.end());
593 reverse_blocks(blocks);
600 unsigned speed_step = speed_quantizer->find_speed_step(speed);
601 if(speed_step!=current_speed_step && !speed_changing && !driver.is_halted() && driver.get_power())
603 speed_changing = true;
604 driver.set_loco_speed(address, speed_step);
609 speed = speed_quantizer->get_speed(current_speed_step);
617 Vehicle &vehicle = *(reverse ? vehicles.back() : vehicles.front());
618 Track *track = vehicle.get_track();
621 for(BlockList::const_iterator i=blocks.begin(); (!ok && i!=cur_blocks_end); ++i)
622 ok = (*i)->has_track(*track);
624 float d = speed*(dt/Time::sec);
627 SetFlag setf(advancing);
628 vehicle.advance(reverse ? -d : d);
630 else if(accurate_position)
633 if(overshoot_dist>40*layout.get_catalogue().get_scale())
635 layout.emergency(name+" has not arrived at sensor");
636 accurate_position = false;
640 else if(end_of_route && cur_blocks_end==blocks.end())
643 signal_arrived.emit();
647 if(!blocks.empty() && !blocks.front()->get_sensor_id())
649 float dist = get_reserved_distance_until(&*blocks.front(), true);
651 if(dist>10*layout.get_catalogue().get_scale())
653 blocks.front()->reserve(0);
659 void Train::save(list<DataFile::Statement> &st) const
661 st.push_back((DataFile::Statement("name"), name));
663 st.push_back((DataFile::Statement("priority"), priority));
665 for(vector<Vehicle *>::const_iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
666 if(i!=vehicles.begin())
667 st.push_back((DataFile::Statement("vehicle"), (*i)->get_type().get_article_number()));
671 DataFile::Statement ss("quantized_speed");
672 speed_quantizer->save(ss.sub);
676 if(!blocks.empty() && cur_blocks_end!=blocks.begin())
678 BlockList blks(blocks.begin(), BlockList::const_iterator(cur_blocks_end));
680 reverse_blocks(blks);
682 BlockIter prev = blks.front().flip();
683 st.push_back((DataFile::Statement("block_hint"), prev->get_id()));
685 for(BlockList::const_iterator i=blks.begin(); i!=blks.end(); ++i)
686 st.push_back((DataFile::Statement("block"), (*i)->get_id()));
691 list<RouteRef>::const_iterator i = routes.begin();
692 for(; (i!=routes.end() && i->route->is_temporary()); ++i) ;
694 st.push_back((DataFile::Statement("route"), i->route->get_name()));
697 // XXX Need more generic way of saving AI state
698 for(list<TrainAI *>::const_iterator i=ais.begin(); i!=ais.end(); ++i)
699 if(Timetable *timetable = dynamic_cast<Timetable *>(*i))
701 DataFile::Statement ss("timetable");
702 timetable->save(ss.sub);
707 void Train::control_changed(const Controller::Control &ctrl)
709 signal_control_changed.emit(ctrl.name, ctrl.value);
712 void Train::loco_speed_event(unsigned addr, unsigned speed, bool rev)
716 current_speed_step = speed;
718 layout.get_driver().set_loco_reverse(address, reverse);
719 speed_changing = false;
724 void Train::loco_func_event(unsigned addr, unsigned func, bool state)
729 functions |= 1<<func;
731 functions &= ~(1<<func);
733 signal_function_changed.emit(func, state);
737 void Train::sensor_event(unsigned addr, bool state)
741 // Find the first sensor block from our reserved blocks that isn't this sensor
742 BlockList::iterator end;
744 for(end=cur_blocks_end; end!=blocks.end(); ++end)
745 if((*end)->get_sensor_id())
747 if((*end)->get_sensor_id()!=addr)
762 // Compute speed and update related state
763 float travel_time_secs = (Time::now()-last_entry_time)/Time::sec;
765 if(pure_speed && speed_quantizer && current_speed_step>0)
766 speed_quantizer->learn(current_speed_step, travel_dist/travel_time_secs, travel_time_secs);
769 for(BlockList::iterator j=cur_blocks_end; j!=end; ++j)
771 travel_dist += (*j)->get_path_length(j->entry());
773 if((*j)->get_sensor_id()==addr && !advancing)
775 TrackIter track = j->track_iter();
778 track = track.flip();
779 vehicles.back()->place(*track, track.entry(), 0, Vehicle::BACK_AXLE);
782 vehicles.front()->place(*track, track.entry(), 0, Vehicle::FRONT_AXLE);
785 last_entry_time = Time::now();
787 accurate_position = true;
790 // Check if we've reached the next route
793 const Route &route = *(++routes.begin())->route;
794 for(BlockList::iterator j=cur_blocks_end; j!=end; ++j)
795 if(route.has_track(*j->track_iter()))
799 signal_route_changed.emit(routes.front().route);
804 // Move blocks up to the next sensor to our current blocks
805 for(BlockList::iterator j=cur_blocks_end; j!=end; ++j)
806 signal_advanced.emit(**j);
807 cur_blocks_end = end;
809 // Try to get more blocks if we're moving
814 layout.emergency("Sensor for "+name+" triggered out of order");
818 const Vehicle &veh = *(reverse ? vehicles.front() : vehicles.back());
820 // Find the first sensor in our current blocks that's still active
821 BlockList::iterator end = blocks.begin();
822 for(BlockList::iterator i=blocks.begin(); i!=cur_blocks_end; ++i)
824 if((*i)->has_track(*veh.get_track()))
826 if((*i)->get_sensor_id())
828 if(layout.get_driver().get_sensor((*i)->get_sensor_id()))
838 if(end!=blocks.begin() && end!=cur_blocks_end)
839 // Free blocks up to the last inactive sensor
840 release_blocks(blocks.begin(), end);
844 void Train::turnout_path_changed(Track &track)
846 for(list<BlockIter>::iterator i=blocks.begin(); i!=blocks.end(); ++i)
847 if((*i)->get_turnout_id()==track.get_turnout_id() && !reserving)
848 check_turnout_paths(false);
851 void Train::halt_event(bool h)
854 accurate_position = false;
857 void Train::block_reserved(const Block &block, const Train *train)
859 if(&block==pending_block && !train && !reserving)
863 void Train::reserve_more()
865 if(!active || blocks.empty() || end_of_route)
868 BlockIter start = blocks.back();
873 // See how many sensor blocks and how much track we already have
876 for(BlockList::const_iterator i=cur_blocks_end; i!=blocks.end(); ++i)
878 if((*i)->get_sensor_id())
881 dist += (*i)->get_path_length(i->entry());
884 list<RouteRef>::iterator cur_route = routes.begin();
885 advance_route(cur_route, *start.track_iter());
887 float approach_margin = 50*layout.get_catalogue().get_scale();
888 float min_dist = controller->get_braking_distance()*1.3+approach_margin*2;
890 BlockIter block = start;
891 list<BlockIter>::iterator good_end = blocks.end();
892 Track *divert_track = 0;
893 bool try_divert = false;
894 Train *blocking_train = 0;
895 BlockList contested_blocks;
897 SetFlag setf(reserving);
901 BlockIter last = block;
902 block = block.next(cur_route!=routes.end() ? cur_route->route : 0);
903 if(!block || block->get_endpoints().size()<2)
907 good_end = blocks.end();
913 TrackIter track = block.track_iter();
915 if(cur_route!=routes.end())
917 if(!advance_route(cur_route, *track))
919 // Keep the blocks if we arrived at the end of the route
922 good_end = blocks.end();
929 if(block->get_turnout_id() && !last->get_turnout_id())
931 /* We can keep the blocks if we arrive at a turnout from a non-turnout
932 block. Having a turnout block as our last reserved block is not good
933 as it would limit our diversion possibilities for little benefit. */
934 good_end = blocks.end();
935 if(nsens>=3 && dist>=min_dist)
941 if(block->get_train()!=blocking_train)
943 if(blocking_train->free_block(*contested_blocks.back()))
945 // Roll back and start actually reserving the blocks
946 block = blocks.back();
947 cur_route = routes.begin();
948 advance_route(cur_route, *block.track_iter().track());
949 if(blocking_train->get_priority()==priority)
950 blocking_train->yield_to(*this);
956 yield_to(*blocking_train);
957 pending_block = contested_blocks.front().block();
958 try_divert = divert_track;
964 contested_blocks.push_back(block);
969 bool reserved = block->reserve(this);
972 /* We've found another train. If it wants to exit the block from the
973 same endpoint we're trying to enter from or the other way around,
974 treat it as coming towards us. Otherwise treat it as going in the
976 Train *other_train = block->get_train();
977 int other_entry = other_train->get_entry_to_block(*block);
979 throw LogicError("Block reservation inconsistency");
981 unsigned exit = block.reverse().entry();
982 unsigned other_exit = BlockIter(block.block(), other_entry).reverse().entry();
983 bool entry_conflict = (block.entry()==other_exit);
984 bool exit_conflict = (exit==static_cast<unsigned>(other_entry));
985 if(!entry_conflict && !last->get_turnout_id())
987 /* The other train is not coming to the blocks we're holding, so we
989 good_end = blocks.end();
991 if(static_cast<unsigned>(other_entry)==block.entry())
992 preceding_train = other_train;
995 int other_prio = other_train->get_priority();
997 if(!entry_conflict && !exit_conflict && other_prio<priority)
999 /* Ask a lesser priority train going to the same direction to free
1001 if(other_train->free_block(*block))
1002 reserved = block->reserve(this);
1004 else if(other_train!=yielding_to && (other_prio<priority || (other_prio==priority && entry_conflict)))
1006 /* A lesser priority train is coming at us, we must ask it to free
1007 enough blocks to get clear of it to avoid a potential deadlock */
1008 blocking_train = other_train;
1009 contested_blocks.clear();
1010 contested_blocks.push_back(block);
1013 else if(divert_track && (entry_conflict || exit_conflict || !other_train->is_active()))
1014 // We are blocked, but there's a diversion possibility
1019 pending_block = &*block;
1024 if(block->get_turnout_id())
1026 const TrackType::Endpoint &track_ep = track.endpoint();
1027 bool multiple_paths = (track_ep.paths&(track_ep.paths-1));
1029 if(multiple_paths && cur_route!=routes.end() && cur_route->diversion!=block->get_turnout_id())
1030 /* There's multiple paths to be taken and we are on a route - take
1031 note of the diversion possibility */
1032 divert_track = &*track;
1035 if(!contested_blocks.empty() && contested_blocks.front()==block)
1036 contested_blocks.pop_front();
1038 blocks.push_back(block);
1040 if(cur_blocks_end==blocks.end())
1042 if(clear_blocks_end==blocks.end())
1044 if(good_end==blocks.end())
1047 if(block->get_sensor_id())
1050 dist += block->get_path_length(block.entry());
1053 // Unreserve blocks that were not good
1054 release_blocks(good_end, blocks.end());
1056 if(blocks.back()!=start)
1057 // We got some new blocks, so no longer need to yield
1060 check_turnout_paths(true);
1062 // Make any sensorless blocks at the beginning immediately current
1063 while(cur_blocks_end!=clear_blocks_end && !(*cur_blocks_end)->get_sensor_id())
1066 if(try_divert && divert(*divert_track))
1070 void Train::check_turnout_paths(bool set)
1072 if(clear_blocks_end==blocks.end())
1075 for(list<BlockIter>::iterator i=clear_blocks_end; i!=blocks.end(); ++i)
1077 if((*i)->get_turnout_id())
1079 TrackIter track = i->track_iter();
1080 const TrackType::Endpoint &track_ep = track.endpoint();
1083 list<BlockIter>::iterator j = i;
1084 if(++j!=blocks.end())
1086 TrackIter rev = j->track_iter().flip();
1087 unsigned mask = rev.endpoint().paths&track_ep.paths;
1088 for(path=0; mask>1; mask>>=1, ++path) ;
1093 if(path!=track->get_active_path())
1096 track->set_active_path(path);
1098 /* Check again, in case the driver was able to service the request
1100 if(!set || path!=track->get_active_path())
1105 if(i==clear_blocks_end)
1110 float Train::get_reserved_distance_until(const Block *until_block, bool back) const
1115 Vehicle &veh = *(reverse!=back ? vehicles.back() : vehicles.front());
1116 const VehicleType &vtype = veh.get_type();
1118 TrackIter track(veh.get_track(), veh.get_entry());
1119 if(!track) // XXX Probably unnecessary
1122 BlockList::const_iterator block = blocks.begin();
1123 while(block!=clear_blocks_end && !(*block)->has_track(*track))
1125 if(block==clear_blocks_end || &**block==until_block)
1128 float result = veh.get_offset();
1130 track = track.reverse();
1132 result = track->get_type().get_path_length(track->get_active_path())-result;
1133 result -= vtype.get_length()/2;
1137 track = track.next();
1141 if(!(*block)->has_track(*track))
1145 if(block==blocks.begin())
1152 if(block==clear_blocks_end)
1156 if(&**block==until_block)
1160 result += track->get_type().get_path_length(track->get_active_path());
1166 void Train::release_blocks()
1168 release_blocks(blocks.begin(), blocks.end());
1171 void Train::release_blocks(BlockList::iterator begin, BlockList::iterator end)
1175 if(begin==cur_blocks_end)
1176 cur_blocks_end = end;
1177 if(begin==clear_blocks_end)
1178 clear_blocks_end = end;
1180 Block &block = **begin;
1181 blocks.erase(begin++);
1184 if(begin==blocks.end())
1185 end_of_route = false;
1189 void Train::reverse_blocks(BlockList &blks) const
1192 for(BlockList::iterator i=blks.begin(); i!=blks.end(); ++i)
1196 bool Train::advance_route(list<RouteRef>::iterator &iter, Track &track)
1198 while(iter!=routes.end() && !iter->route->has_track(track))
1200 if(iter==routes.end())
1203 list<RouteRef>::iterator next = iter;
1205 if(next!=routes.end() && next->diversion && next->route->has_track(track))
1211 Route *Train::create_lead_route(Route *lead, const Route *target)
1215 lead = new Route(layout);
1216 lead->set_name("Lead");
1217 lead->set_temporary(true);
1220 set<Track *> tracks;
1221 for(BlockList::iterator i=blocks.begin(); i!=blocks.end(); ++i)
1223 const set<Track *> &btracks = (*i)->get_tracks();
1224 for(set<Track *>::const_iterator j=btracks.begin(); j!=btracks.end(); ++j)
1225 if(!target || !target->has_track(**j))
1229 lead->add_tracks(tracks);
1234 bool Train::is_valid_diversion(const Route &diversion, const TrackIter &from)
1236 float diversion_len = 0;
1237 TrackLoopIter track1 = from;
1238 while(diversion.has_track(*track1))
1240 unsigned path = diversion.get_path(*track1);
1241 diversion_len += track1->get_type().get_path_length(path);
1243 track1 = track1.next(path);
1245 if(!track1 || track1.looped())
1249 list<RouteRef>::iterator route = routes.begin();
1250 if(!advance_route(route, *from))
1253 float route_len = 0;
1254 TrackLoopIter track2 = from;
1257 unsigned path = route->route->get_path(*track2);
1258 route_len += track2->get_type().get_path_length(path);
1260 bool ok = (track2!=from && diversion.has_track(*track2));
1262 track2 = track2.next(path);
1272 if(!advance_route(route, *track2))
1276 // Must end up at the same place through both routes
1280 return diversion_len<route_len*1.2;
1284 Train::RouteRef::RouteRef(const Route *r, unsigned d):
1290 Train::Loader::Loader(Train &t):
1291 DataFile::BasicLoader<Train>(t),
1295 add("block", &Loader::block);
1296 add("block_hint", &Loader::block_hint);
1297 add("name", &Loader::name);
1298 add("priority", &Train::priority);
1299 add("quantized_speed", &Loader::quantized_speed);
1300 add("route", &Loader::route);
1301 add("timetable", &Loader::timetable);
1302 add("vehicle", &Loader::vehicle);
1305 void Train::Loader::finish()
1307 if(!obj.blocks.empty())
1309 TrackIter track = obj.blocks.front().track_iter();
1310 float offset = 2*obj.layout.get_catalogue().get_scale();
1311 obj.vehicles.back()->place(*track, track.entry(), offset, Vehicle::BACK_BUFFER);
1315 void Train::Loader::block(unsigned id)
1323 blk = &obj.layout.get_block(id);
1325 catch(const KeyError &)
1327 blocks_valid = false;
1333 entry = blk->get_endpoint_by_link(*prev_block);
1338 obj.blocks.push_back(BlockIter(blk, entry));
1340 if(blk->get_sensor_id())
1341 obj.layout.get_driver().set_sensor(blk->get_sensor_id(), true);
1346 void Train::Loader::block_hint(unsigned id)
1350 prev_block = &obj.layout.get_block(id);
1352 catch(const KeyError &)
1354 blocks_valid = false;
1358 void Train::Loader::name(const string &n)
1363 void Train::Loader::quantized_speed()
1365 if(obj.speed_quantizer)
1366 load_sub(*obj.speed_quantizer);
1369 void Train::Loader::route(const string &n)
1371 obj.set_route(&obj.layout.get_route(n));
1374 void Train::Loader::timetable()
1376 Timetable *ttbl = new Timetable(obj);
1380 void Train::Loader::vehicle(ArticleNumber art_nr)
1382 const VehicleType &vtype = obj.layout.get_catalogue().get_vehicle(art_nr);
1383 Vehicle *veh = new Vehicle(obj.layout, vtype);
1384 obj.vehicles.back()->attach_back(*veh);
1385 obj.vehicles.push_back(veh);