3 #include <msp/strings/format.h>
4 #include <msp/time/units.h>
5 #include <msp/time/utils.h>
11 #include "simplecontroller.h"
12 #include "speedquantizer.h"
13 #include "timetable.h"
14 #include "trackiter.h"
15 #include "tracktype.h"
18 #include "vehicletype.h"
30 SetFlag(bool &f): flag(f) { flag = true; }
31 ~SetFlag() { flag = false; }
39 Train::Train(Layout &l, const VehicleType &t, unsigned a, const string &p):
47 cur_blocks_end(blocks.end()),
48 clear_blocks_end(blocks.end()),
52 controller(new SimpleController),
54 current_speed_step(0),
55 speed_changing(false),
62 accurate_position(false),
65 if(!loco_type.is_locomotive())
66 throw InvalidParameterValue("Initial vehicle must be a locomotive");
68 unsigned speed_steps = layout.get_driver().get_protocol_speed_steps(protocol);
70 speed_quantizer = new SpeedQuantizer(speed_steps);
72 vehicles.push_back(new Vehicle(layout, loco_type));
74 layout.add_train(*this);
76 layout.get_driver().add_loco(address, protocol, loco_type);
77 layout.get_driver().signal_loco_speed.connect(sigc::mem_fun(this, &Train::loco_speed_event));
78 layout.get_driver().signal_loco_function.connect(sigc::mem_fun(this, &Train::loco_func_event));
80 layout.signal_block_reserved.connect(sigc::mem_fun(this, &Train::block_reserved));
81 layout.signal_block_state_changed.connect(sigc::mem_fun(this, &Train::block_state_changed));
83 layout.get_driver().signal_halt.connect(sigc::mem_fun(this, &Train::halt_event));
85 const set<Track *> &tracks = layout.get_tracks();
86 for(set<Track *>::const_iterator i=tracks.begin(); i!=tracks.end(); ++i)
87 if((*i)->get_turnout_id())
88 (*i)->signal_path_changed.connect(sigc::hide(sigc::bind(sigc::mem_fun(this, &Train::turnout_path_changed), sigc::ref(**i))));
90 controller->signal_control_changed.connect(sigc::mem_fun(this, &Train::control_changed));
96 for(vector<Vehicle *>::iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
98 layout.remove_train(*this);
101 void Train::set_name(const string &n)
105 signal_name_changed.emit(name);
108 void Train::set_priority(int p)
113 void Train::yield_to(const Train &t)
118 void Train::add_vehicle(const VehicleType &vt)
120 Vehicle *veh = new Vehicle(layout, vt);
121 vehicles.back()->attach_back(*veh);
122 vehicles.push_back(veh);
125 void Train::remove_vehicle(unsigned i)
127 if(i>=vehicles.size())
128 throw InvalidParameterValue("Vehicle index out of range");
130 throw InvalidParameterValue("Can't remove the locomotive");
132 vehicles.erase(vehicles.begin()+i);
133 if(i<vehicles.size())
134 vehicles[i-1]->attach_back(*vehicles[i]);
137 unsigned Train::get_n_vehicles() const
139 return vehicles.size();
142 Vehicle &Train::get_vehicle(unsigned i)
144 if(i>=vehicles.size())
145 throw InvalidParameterValue("Vehicle index out of range");
149 const Vehicle &Train::get_vehicle(unsigned i) const
151 if(i>=vehicles.size())
152 throw InvalidParameterValue("Vehicle index out of range");
156 void Train::set_control(const string &n, float v)
158 controller->set_control(n, v);
161 void Train::set_active(bool a)
165 if(!a && controller->get_speed())
166 throw InvalidState("Can't deactivate while moving");
171 stop_timeout = Time::TimeStamp();
175 stop_timeout = Time::now()+2*Time::sec;
178 void Train::set_function(unsigned func, bool state)
180 if(!loco_type.get_functions().count(func))
181 throw InvalidParameterValue("Invalid function");
182 layout.get_driver().set_loco_function(address, func, state);
185 float Train::get_control(const string &ctrl) const
187 return controller->get_control(ctrl).value;
190 float Train::get_speed() const
192 return controller->get_speed();
195 float Train::get_quantized_speed() const
198 return speed_quantizer->quantize_speed(controller->get_speed());
200 return controller->get_speed();
203 bool Train::get_function(unsigned func) const
205 return (functions>>func)&1;
208 void Train::add_ai(TrainAI &ai)
211 ai.signal_event.connect(sigc::bind<0>(signal_ai_event, sigc::ref(ai)));
214 void Train::remove_ai(TrainAI &ai)
216 list<TrainAI *>::iterator i = find(ais.begin(), ais.end(), &ai);
221 TrainAI *Train::get_tagged_ai(const string &tag) const
223 for(list<TrainAI *>::const_iterator i=ais.begin(); i!=ais.end(); ++i)
224 if((*i)->get_tag()==tag)
230 void Train::ai_message(const TrainAI::Message &msg)
232 for(list<TrainAI *>::iterator i=ais.begin(); i!=ais.end(); ++i)
236 bool Train::set_route(const Route *r)
238 free_noncritical_blocks();
241 if(r && !blocks.empty())
243 TrackIter first = blocks.front().track_iter();
244 TrackIter next = blocks.back().next().track_iter();
245 if(!r->has_track(*next))
247 lead = Route::find(next, *r);
250 create_lead_route(lead, lead);
251 routes.push_front(lead);
253 else if(!r->has_track(*first))
254 lead = create_lead_route(0, r);
259 routes.push_back(lead);
262 end_of_route = false;
266 signal_route_changed.emit(get_route());
271 bool Train::go_to(Track &to)
273 for(BlockList::const_iterator i=blocks.begin(); i!=cur_blocks_end; ++i)
274 if((*i)->has_track(to))
276 signal_arrived.emit();
280 free_noncritical_blocks();
282 TrackIter next = blocks.back().next().track_iter();
284 Route *route = Route::find(next, to);
287 create_lead_route(route, route);
288 return set_route(route);
291 bool Train::go_to(const Zone &to)
294 for(BlockList::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
295 tracks.insert((*i)->get_tracks().begin(), (*i)->get_tracks().end());
297 const Zone::TrackSet &ztracks = to.get_tracks();
298 unsigned union_size = 0;
299 for(Zone::TrackSet::const_iterator i=ztracks.begin(); i!=ztracks.end(); ++i)
300 union_size += tracks.count(*i);
302 if(union_size==tracks.size() || union_size==ztracks.size())
304 signal_arrived.emit();
308 free_noncritical_blocks();
310 TrackIter next = blocks.back().next().track_iter();
312 Route *route = Route::find(next, to);
315 create_lead_route(route, route);
316 route->add_tracks(ztracks);
317 return set_route(route);
320 bool Train::divert(Track &from)
322 if(!from.get_turnout_id())
323 throw InvalidParameterValue("Can't divert from a non-turnout");
329 list<RouteRef>::iterator route = routes.begin();
331 // Follow our routes to find out where we're entering the turnout
332 for(TrackLoopIter track = blocks.front().track_iter();;)
334 if(!advance_route(route, *track))
339 Block &block = track->get_block();
340 if(block.get_train()==this && !free_block(block))
343 int route_path = route->route->get_turnout(from.get_turnout_id());
345 // Check that more than one path is available
346 unsigned ep_paths = track.endpoint().paths;
347 if(!(ep_paths&(ep_paths-1)))
350 // Choose some other path
351 for(int i=0; ep_paths>>i; ++i)
352 if((ep_paths&(1<<i)) && i!=route_path)
358 entry = track.entry();
362 track = track.next(route->route->get_path(*track));
364 if(!track || track.looped())
368 TrackIter track = TrackIter(&from, entry).next(path);
373 for(list<RouteRef>::iterator i=routes.begin(); i!=routes.end(); ++i)
374 tracks.insert(i->route->get_tracks().begin(), i->route->get_tracks().end());
375 RefPtr<Route> diversion = Route::find(track, tracks);
379 diversion->set_name("Diversion");
380 diversion->add_track(from);
381 diversion->set_turnout(from.get_turnout_id(), path);
383 if(!is_valid_diversion(*diversion, TrackIter(&from, entry)))
386 // Follow the diversion route until we get back to the original route
387 list<RouteRef>::iterator end = routes.end();
390 for(list<RouteRef>::iterator i=route; (end==routes.end() && i!=routes.end()); ++i)
391 if(i->route->has_track(*track))
394 if(end!=routes.end())
396 else if(!diversion->has_track(*track))
397 throw LogicError("Pathfinder returned a bad route");
399 track = track.next(diversion->get_path(*track));
403 // We are rejoining the same route we diverted from, duplicate it
404 routes.insert(end, *route);
408 routes.erase(route, end);
410 routes.insert(end, RouteRef(diversion.release(), from.get_turnout_id()));
415 const Route *Train::get_route() const
419 return routes.front().route;
422 void Train::place(Block &block, unsigned entry)
424 if(controller->get_speed())
425 throw InvalidState("Must be stopped before placing");
430 accurate_position = false;
432 if(!block.reserve(this))
435 blocks.push_back(BlockIter(&block, entry));
438 TrackIter track = BlockIter(&block, entry).reverse().track_iter();
439 vehicles.front()->place(*track, track.entry(), 0, Vehicle::FRONT_BUFFER);
443 const Block::Endpoint &bep = block.get_endpoint(entry);
444 vehicles.back()->place(*bep.track, bep.track_ep, 0, Vehicle::BACK_BUFFER);
448 void Train::unplace()
450 if(controller->get_speed())
451 throw InvalidState("Must be stopped before unplacing");
456 accurate_position = false;
458 for(vector<Vehicle *>::iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
462 bool Train::free_block(Block &block)
464 if(get_reserved_distance_until(&block, false)<controller->get_braking_distance()*1.3)
468 for(BlockList::iterator i=cur_blocks_end; i!=blocks.end(); ++i)
470 if(i->block()==&block)
474 release_blocks(i, blocks.end());
477 else if((*i)->get_sensor_id())
484 void Train::free_noncritical_blocks()
489 if(controller->get_speed()==0)
491 release_blocks(cur_blocks_end, blocks.end());
495 float margin = 10*layout.get_catalogue().get_scale();
496 float min_dist = controller->get_braking_distance()*1.3+margin;
498 Vehicle &veh = *(reverse ? vehicles.back() : vehicles.front());
500 TrackIter track(veh.get_track(), veh.get_entry());
501 BlockList::iterator block = blocks.begin();
503 while(block!=blocks.end() && !(*block)->has_track(*track))
506 if(block==cur_blocks_end)
510 float dist = veh.get_offset();
514 dist = track->get_type().get_path_length(track->get_active_path())-dist;
515 dist -= veh.get_type().get_length()/2;
520 track = track.next();
522 if(!(*block)->has_track(*track))
525 if(block==cur_blocks_end)
527 if(block==blocks.end())
530 if(dist>min_dist && nsens>0)
532 release_blocks(block, blocks.end());
536 if(in_rsv && (*block)->get_sensor_id())
540 dist += track->get_type().get_path_length(track->get_active_path());
544 int Train::get_entry_to_block(Block &block) const
546 for(BlockList::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
547 if(i->block()==&block)
552 float Train::get_reserved_distance() const
558 TrackIter next = blocks.back().next().track_iter();
559 if(next && next->get_type().is_turnout())
560 margin = 15*layout.get_catalogue().get_scale();
562 return max(get_reserved_distance_until(0, false)-margin, 0.0f);
565 void Train::tick(const Time::TimeStamp &t, const Time::TimeDelta &dt)
567 if(!active && stop_timeout && t>=stop_timeout)
569 release_blocks(cur_blocks_end, blocks.end());
570 stop_timeout = Time::TimeStamp();
573 Driver &driver = layout.get_driver();
575 for(list<TrainAI *>::iterator i=ais.begin(); i!=ais.end(); ++i)
577 controller->tick(dt);
578 float speed = controller->get_speed();
579 bool moving = speed>0;
581 if(controller->get_reverse()!=reverse)
583 reverse = controller->get_reverse();
585 if(loco_type.get_swap_direction())
587 driver.set_loco_reverse(address, r);
589 release_blocks(cur_blocks_end, blocks.end());
590 reverse_blocks(blocks);
597 unsigned speed_step = speed_quantizer->find_speed_step(speed);
598 if(speed_step!=current_speed_step && !speed_changing && !driver.is_halted() && driver.get_power())
600 speed_changing = true;
601 driver.set_loco_speed(address, speed_step);
606 speed = speed_quantizer->get_speed(current_speed_step);
614 Vehicle &vehicle = *(reverse ? vehicles.back() : vehicles.front());
615 Track *track = vehicle.get_track();
618 for(BlockList::const_iterator i=blocks.begin(); (!ok && i!=cur_blocks_end); ++i)
619 ok = (*i)->has_track(*track);
621 float d = speed*(dt/Time::sec);
624 SetFlag setf(advancing);
625 vehicle.advance(reverse ? -d : d);
627 else if(accurate_position)
630 if(overshoot_dist>40*layout.get_catalogue().get_scale())
632 layout.emergency(name+" has not arrived at sensor");
633 accurate_position = false;
637 else if(end_of_route && cur_blocks_end==blocks.end())
640 signal_arrived.emit();
644 if(!blocks.empty() && !blocks.front()->get_sensor_id())
646 float dist = get_reserved_distance_until(&*blocks.front(), true);
648 if(dist>10*layout.get_catalogue().get_scale())
650 blocks.front()->reserve(0);
656 void Train::save(list<DataFile::Statement> &st) const
658 st.push_back((DataFile::Statement("name"), name));
660 st.push_back((DataFile::Statement("priority"), priority));
662 for(vector<Vehicle *>::const_iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
663 if(i!=vehicles.begin())
664 st.push_back((DataFile::Statement("vehicle"), (*i)->get_type().get_article_number()));
668 DataFile::Statement ss("quantized_speed");
669 speed_quantizer->save(ss.sub);
673 if(!blocks.empty() && cur_blocks_end!=blocks.begin())
675 BlockList blks(blocks.begin(), BlockList::const_iterator(cur_blocks_end));
677 reverse_blocks(blks);
679 BlockIter prev = blks.front().flip();
680 st.push_back((DataFile::Statement("block_hint"), prev->get_id()));
682 for(BlockList::const_iterator i=blks.begin(); i!=blks.end(); ++i)
683 st.push_back((DataFile::Statement("block"), (*i)->get_id()));
688 list<RouteRef>::const_iterator i = routes.begin();
689 for(; (i!=routes.end() && i->route->is_temporary()); ++i) ;
691 st.push_back((DataFile::Statement("route"), i->route->get_name()));
694 // XXX Need more generic way of saving AI state
695 for(list<TrainAI *>::const_iterator i=ais.begin(); i!=ais.end(); ++i)
696 if(Timetable *timetable = dynamic_cast<Timetable *>(*i))
698 DataFile::Statement ss("timetable");
699 timetable->save(ss.sub);
704 void Train::control_changed(const Controller::Control &ctrl)
706 signal_control_changed.emit(ctrl.name, ctrl.value);
709 void Train::loco_speed_event(unsigned addr, unsigned speed, bool rev)
713 current_speed_step = speed;
715 if(loco_type.get_swap_direction())
718 layout.get_driver().set_loco_reverse(address, r);
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::block_state_changed(Block &block, Block::State state)
739 if(state==Block::MAYBE_ACTIVE)
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())
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 && travel_time_secs>=2)
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==&block && !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");
816 else if(state==Block::INACTIVE)
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);