3 This file is part of the MSP Märklin suite
4 Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa
5 Distributed under the GPL
9 #include <msp/strings/formatter.h>
10 #include <msp/time/units.h>
11 #include <msp/time/utils.h>
12 #include "aicontrol.h"
13 #include "catalogue.h"
17 #include "simplecontroller.h"
18 #include "timetable.h"
19 #include "tracktype.h"
22 #include "vehicletype.h"
33 SetFlag(bool &f): flag(f) { flag = true; }
34 ~SetFlag() { flag = false; }
42 Train::Train(Layout &l, const VehicleType &t, unsigned a):
51 controller(new AIControl(*this, new SimpleController)),
55 speed_changing(false),
63 accurate_position(false),
66 if(!loco_type.is_locomotive())
67 throw InvalidParameterValue("Initial vehicle must be a locomotive");
69 vehicles.push_back(new Vehicle(layout, loco_type));
71 layout.add_train(*this);
73 layout.get_driver().add_loco(address);
74 layout.get_driver().signal_loco_speed.connect(sigc::mem_fun(this, &Train::loco_speed_event));
75 layout.get_driver().signal_loco_function.connect(sigc::mem_fun(this, &Train::loco_func_event));
77 layout.signal_block_reserved.connect(sigc::mem_fun(this, &Train::block_reserved));
78 layout.get_driver().signal_sensor.connect(sigc::mem_fun(this, &Train::sensor_event));
79 layout.get_driver().signal_turnout.connect(sigc::mem_fun(this, &Train::turnout_event));
81 layout.get_driver().signal_halt.connect(sigc::mem_fun(this, &Train::halt_event));
83 controller->signal_control_changed.connect(sigc::mem_fun(this, &Train::control_changed));
90 for(vector<Vehicle *>::iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
92 layout.remove_train(*this);
95 void Train::set_name(const string &n)
99 signal_name_changed.emit(name);
102 void Train::set_priority(int p)
107 void Train::yield_to(const Train &t)
112 void Train::add_vehicle(const VehicleType &vt)
114 Vehicle *veh = new Vehicle(layout, vt);
115 vehicles.back()->attach_back(*veh);
116 vehicles.push_back(veh);
119 void Train::remove_vehicle(unsigned i)
121 if(i>=vehicles.size())
122 throw InvalidParameterValue("Vehicle index out of range");
124 throw InvalidParameterValue("Can't remove the locomotive");
126 vehicles.erase(vehicles.begin()+i);
127 if(i<vehicles.size())
128 vehicles[i-1]->attach_back(*vehicles[i]);
131 unsigned Train::get_n_vehicles() const
133 return vehicles.size();
136 Vehicle &Train::get_vehicle(unsigned i)
138 if(i>=vehicles.size())
139 throw InvalidParameterValue("Vehicle index out of range");
143 const Vehicle &Train::get_vehicle(unsigned i) const
145 if(i>=vehicles.size())
146 throw InvalidParameterValue("Vehicle index out of range");
150 void Train::set_control(const string &n, float v)
152 controller->set_control(n, v);
155 void Train::set_active(bool a)
159 if(!a && controller->get_speed())
160 throw InvalidState("Can't deactivate while moving");
165 stop_timeout = Time::TimeStamp();
170 stop_timeout = Time::now()+2*Time::sec;
171 set_status("Stopped");
175 void Train::set_function(unsigned func, bool state)
177 if(!loco_type.get_functions().count(func))
178 throw InvalidParameterValue("Invalid function");
180 layout.get_driver().set_loco_function(address, func, state);
182 layout.get_driver().set_loco_function(address+1, func-4, 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 bool Train::get_function(unsigned func) const
197 return (functions>>func)&1;
200 void Train::set_timetable(Timetable *tt)
206 void Train::set_route(const Route *r)
208 free_noncritical_blocks();
213 end_of_route = false;
215 if(r && !cur_blocks.empty())
217 BlockRef &first = cur_blocks.front();
218 BlockRef &last = (rsv_blocks.empty() ? cur_blocks.back() : rsv_blocks.back());
219 BlockRef next = last.next();
220 const Block::Endpoint &first_ep = first.block->get_endpoints()[first.entry];
221 const Block::Endpoint &next_ep = next.block->get_endpoints()[next.entry];
222 if(!r->get_tracks().count(next_ep.track))
224 Route *lead = Route::find(*next_ep.track, next_ep.track_ep, *r);
225 create_lead_route(lead, lead);
226 routes.push_front(lead);
228 else if(!r->get_tracks().count(first_ep.track))
229 routes.push_front(create_lead_route(0, r));
234 signal_route_changed.emit(get_route());
237 void Train::go_to(Track &to)
239 for(list<BlockRef>::const_iterator i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
240 if(i->block->get_tracks().count(&to))
242 signal_arrived.emit();
247 free_noncritical_blocks();
249 BlockRef &last = (rsv_blocks.empty() ? cur_blocks.back() : rsv_blocks.back());
250 BlockRef next = last.next();
251 const Block::Endpoint &ep = next.block->get_endpoints()[next.entry];
253 Route *route = Route::find(*ep.track, ep.track_ep, to);
254 create_lead_route(route, route);
258 bool Train::divert(Track &from)
260 if(!from.get_turnout_id())
261 throw InvalidParameterValue("Can't divert from a non-turnout");
266 unsigned from_ep = 0;
267 list<RouteRef>::iterator route = routes.begin();
268 Block *block = cur_blocks.back().block;
269 unsigned entry = cur_blocks.back().entry;
270 set<const Track *> visited;
272 // Follow our routes to find out where we're entering the turnout
275 Block *link = block->get_link(block->traverse(entry, route->route));
276 entry = link->get_endpoint_by_link(*block);
279 const Block::Endpoint &entry_ep = block->get_endpoints()[entry];
281 if(visited.count(entry_ep.track))
283 visited.insert(entry_ep.track);
285 if(!advance_route(route, *entry_ep.track))
288 if(entry_ep.track==&from)
290 if(block->get_train()==this && !free_block(*block))
293 from_ep = entry_ep.track_ep;
294 path = route->route->get_turnout(from.get_turnout_id());
299 // Check that more than one path is available
300 unsigned ep_paths = from.get_type().get_endpoints()[from_ep].paths;
301 if(!(ep_paths&(ep_paths-1)))
304 // Choose some other path
305 for(int i=0; ep_paths>>i; ++i)
306 if((ep_paths&(1<<i)) && i!=path)
312 Track *track = from.get_link(from.traverse(from_ep, path));
316 unsigned ep = track->get_endpoint_by_link(from);
319 for(list<RouteRef>::iterator i=routes.begin(); i!=routes.end(); ++i)
320 tracks.insert(i->route->get_tracks().begin(), i->route->get_tracks().end());
321 Route *diversion = 0;
324 diversion = Route::find(*track, ep, tracks);
326 catch(const Msp::Exception &)
331 diversion->set_name("Diversion");
332 diversion->add_track(from);
333 diversion->set_turnout(from.get_turnout_id(), path);
335 if(!is_valid_diversion(*diversion, from, from_ep))
341 // Follow the diversion route until we get back to the original route
342 list<RouteRef>::iterator end = routes.end();
346 if(track->get_turnout_id())
347 path = diversion->get_turnout(track->get_turnout_id());
348 Track *next = track->get_link(track->traverse(ep, path));
350 for(list<RouteRef>::iterator i=route; (end==routes.end() && i!=routes.end()); ++i)
351 if(i->route->get_tracks().count(next))
354 if(end!=routes.end())
356 else if(!diversion->get_tracks().count(next))
357 throw Exception("Pathfinder returned a bad route");
359 ep = next->get_endpoint_by_link(*track);
364 // We are rejoining the same route we diverted from, duplicate it
365 routes.insert(end, *route);
369 routes.erase(route, end);
371 routes.insert(end, RouteRef(diversion, from.get_turnout_id()));
376 const Route *Train::get_route() const
380 return routes.front().route;
383 void Train::place(Block &block, unsigned entry)
385 if(controller->get_speed())
386 throw InvalidState("Must be stopped before placing");
388 release_blocks(rsv_blocks);
389 release_blocks(cur_blocks);
392 accurate_position = false;
394 if(!block.reserve(this))
396 set_status("Unplaced");
400 cur_blocks.push_back(BlockRef(&block, entry));
403 unsigned exit = block.traverse(entry);
404 const Block::Endpoint &bep = block.get_endpoints()[exit];
405 Track *track = bep.track->get_link(bep.track_ep);
406 unsigned ep = track->get_endpoint_by_link(*bep.track);
407 vehicles.front()->place(*track, ep, 0, Vehicle::FRONT_BUFFER);
411 const Block::Endpoint &bep = block.get_endpoints()[entry];
412 vehicles.back()->place(*bep.track, bep.track_ep, 0, Vehicle::BACK_BUFFER);
416 void Train::unplace()
418 if(controller->get_speed())
419 throw InvalidState("Must be stopped before unplacing");
421 release_blocks(rsv_blocks);
422 release_blocks(cur_blocks);
425 accurate_position = false;
427 for(vector<Vehicle *>::iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
430 set_status("Unplaced");
433 bool Train::free_block(Block &block)
435 float margin = 10*layout.get_catalogue().get_scale();
436 if(get_reserved_distance_until(&block, false)<controller->get_braking_distance()*1.3+margin)
440 for(list<BlockRef>::iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
446 release_blocks(rsv_blocks, i, rsv_blocks.end());
449 else if(i->block->get_sensor_id())
456 void Train::free_noncritical_blocks()
458 if(cur_blocks.empty() || rsv_blocks.empty())
461 if(controller->get_speed()==0)
463 release_blocks(rsv_blocks);
467 float margin = 10*layout.get_catalogue().get_scale();
468 float min_dist = controller->get_braking_distance()*1.3+margin;
470 Vehicle &veh = *(reverse ? vehicles.back() : vehicles.front());
472 Track *track = veh.get_track();
473 list<BlockRef>::iterator block = cur_blocks.begin();
475 while(block!=rsv_blocks.end() && !block->block->get_tracks().count(track))
478 if(block==cur_blocks.end())
480 block = rsv_blocks.begin();
485 unsigned entry = veh.get_entry();
486 float dist = veh.get_offset();
488 entry = track->traverse(entry);
490 dist = track->get_type().get_path_length(track->get_active_path())-dist;
491 dist -= veh.get_type().get_length()/2;
496 Track *next = track->get_link(track->traverse(entry));
497 entry = next->get_endpoint_by_link(*track);
500 if(!block->block->get_tracks().count(track))
503 if(block==cur_blocks.end())
505 block = rsv_blocks.begin();
508 if(block==rsv_blocks.end())
511 if(dist>min_dist && nsens>0)
513 release_blocks(rsv_blocks, block, rsv_blocks.end());
517 if(in_rsv && block->block->get_sensor_id())
521 dist += track->get_type().get_path_length(track->get_active_path());
525 int Train::get_entry_to_block(Block &block) const
527 for(list<BlockRef>::const_iterator i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
530 for(list<BlockRef>::const_iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
536 float Train::get_reserved_distance() const
538 return get_reserved_distance_until(0, false);
541 void Train::tick(const Time::TimeStamp &t, const Time::TimeDelta &dt)
543 if(!active && stop_timeout && t>=stop_timeout)
545 release_blocks(rsv_blocks);
546 end_of_route = false;
547 stop_timeout = Time::TimeStamp();
550 Driver &driver = layout.get_driver();
554 controller->tick(dt);
555 float speed = controller->get_speed();
556 unsigned speed_notch = find_speed(speed);
558 if(controller->get_reverse()!=reverse)
560 reverse = controller->get_reverse();
561 driver.set_loco_reverse(address, reverse);
563 release_blocks(rsv_blocks);
564 reverse_blocks(cur_blocks);
568 if(speed_notch!=current_speed && !speed_changing && !driver.is_halted() && driver.get_power())
570 speed_changing = true;
571 driver.set_loco_speed(address, speed_notch);
576 set_status(format("Traveling %d kmh", get_travel_speed()));
578 set_status("Waiting");
586 Vehicle &vehicle = *(reverse ? vehicles.back() : vehicles.front());
587 Track *track = vehicle.get_track();
590 for(list<BlockRef>::const_iterator i=cur_blocks.begin(); (!ok && i!=cur_blocks.end()); ++i)
591 ok = i->block->get_tracks().count(track);
593 float d = get_real_speed(current_speed)*(dt/Time::sec);
596 SetFlag setf(advancing);
597 vehicle.advance(reverse ? -d : d);
599 else if(accurate_position)
602 if(overshoot_dist>40*layout.get_catalogue().get_scale())
604 layout.emergency(name+" has not arrived at sensor");
605 accurate_position = false;
609 else if(end_of_route && rsv_blocks.empty())
612 signal_arrived.emit();
616 if(!cur_blocks.empty() && !cur_blocks.front().block->get_sensor_id())
618 float dist = get_reserved_distance_until(cur_blocks.front().block, true);
620 if(dist>10*layout.get_catalogue().get_scale())
622 cur_blocks.front().block->reserve(0);
623 cur_blocks.pop_front();
628 void Train::save(list<DataFile::Statement> &st) const
630 st.push_back((DataFile::Statement("name"), name));
632 st.push_back((DataFile::Statement("priority"), priority));
634 for(vector<Vehicle *>::const_iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
635 if(i!=vehicles.begin())
636 st.push_back((DataFile::Statement("vehicle"), (*i)->get_type().get_article_number()));
638 for(unsigned i=0; i<=14; ++i)
639 if(real_speed[i].weight)
640 st.push_back((DataFile::Statement("real_speed"), i, real_speed[i].speed, real_speed[i].weight));
642 if(!cur_blocks.empty())
644 list<BlockRef> blocks = cur_blocks;
646 reverse_blocks(blocks);
648 Block *prev = blocks.front().block->get_endpoints()[blocks.front().entry].link;
649 st.push_back((DataFile::Statement("block_hint"), prev->get_id()));
651 for(list<BlockRef>::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
652 st.push_back((DataFile::Statement("block"), i->block->get_id()));
657 list<RouteRef>::const_iterator i = routes.begin();
658 for(; (i!=routes.end() && i->route->is_temporary()); ++i) ;
660 st.push_back((DataFile::Statement("route"), i->route->get_name()));
665 DataFile::Statement ss("timetable");
666 timetable->save(ss.sub);
671 void Train::control_changed(const Controller::Control &ctrl)
673 signal_control_changed.emit(ctrl.name, ctrl.value);
676 void Train::loco_speed_event(unsigned addr, unsigned speed, bool)
680 current_speed = speed;
681 speed_changing = false;
686 void Train::loco_func_event(unsigned addr, unsigned func, bool state)
688 if(addr==address || (addr==address+1 && loco_type.get_max_function()>4))
693 functions |= 1<<func;
695 functions &= ~(1<<func);
697 signal_function_changed.emit(func, state);
701 void Train::sensor_event(unsigned addr, bool state)
705 // Find the first sensor block from our reserved blocks that isn't this sensor
706 list<BlockRef>::iterator i;
708 for(i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
709 if(i->block->get_sensor_id())
711 if(i->block->get_sensor_id()!=addr)
724 if(result==1 && i!=rsv_blocks.begin())
726 // Compute speed and update related state
727 float travel_time_secs = (Time::now()-last_entry_time)/Time::sec;
733 RealSpeed &rs = real_speed[current_speed];
734 rs.add(travel_dist/travel_time_secs, travel_time_secs);
736 set_status(format("Traveling %d kmh", get_travel_speed()));
741 for(list<BlockRef>::iterator j=rsv_blocks.begin(); j!=i; ++j)
743 j->block->traverse(j->entry, &block_len);
744 travel_dist += block_len;
746 if(j->block->get_sensor_id()==addr && !advancing)
748 const Block::Endpoint &bep = j->block->get_endpoints()[j->entry];
751 Track *track = bep.track->get_link(bep.track_ep);
752 unsigned ep = track->get_endpoint_by_link(*bep.track);
753 vehicles.back()->place(*track, ep, 0, Vehicle::BACK_AXLE);
756 vehicles.front()->place(*bep.track, bep.track_ep, 0, Vehicle::FRONT_AXLE);
759 last_entry_time = Time::now();
761 accurate_position = true;
764 // Check if we've reached the next route
767 const set<Track *> &rtracks = (++routes.begin())->route->get_tracks();
768 for(list<BlockRef>::iterator j=rsv_blocks.begin(); j!=i; ++j)
769 if(rtracks.count(j->block->get_endpoints()[j->entry].track))
773 signal_route_changed.emit(routes.front().route);
778 // Move blocks up to the next sensor to our current blocks
779 cur_blocks.splice(cur_blocks.end(), rsv_blocks, rsv_blocks.begin(), i);
781 // Try to get more blocks if we're moving
786 layout.emergency("Sensor for "+name+" triggered out of order");
790 const Vehicle &veh = *(reverse ? vehicles.front() : vehicles.back());
792 // Find the first sensor in our current blocks that's still active
793 list<BlockRef>::iterator end = cur_blocks.begin();
794 for(list<BlockRef>::iterator i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
796 if(i->block->get_tracks().count(veh.get_track()))
798 if(i->block->get_sensor_id())
800 if(layout.get_driver().get_sensor(i->block->get_sensor_id()))
810 if(end!=cur_blocks.begin() && end!=cur_blocks.end())
811 // Free blocks up to the last inactive sensor
812 release_blocks(cur_blocks, cur_blocks.begin(), end);
816 void Train::turnout_event(unsigned addr, bool)
818 if(pending_block && (!pending_block->get_train() || pending_block->get_train()==this))
820 unsigned pending_addr = pending_block->get_turnout_id();
821 bool double_addr = (*pending_block->get_tracks().begin())->get_type().is_double_address();
822 if(addr==pending_addr || (double_addr && addr==pending_addr+1))
832 void Train::halt_event(bool h)
835 accurate_position = false;
838 void Train::block_reserved(const Block &block, const Train *train)
840 if(&block==pending_block && !train && !reserving)
844 unsigned Train::reserve_more()
850 if(!rsv_blocks.empty())
851 start = &rsv_blocks.back();
852 else if(!cur_blocks.empty())
853 start = &cur_blocks.back();
859 // See how many sensor blocks and how much track we already have
862 for(list<BlockRef>::const_iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
864 if(i->block->get_sensor_id())
869 i->block->traverse(i->entry, &length);
877 list<RouteRef>::iterator cur_route = routes.begin();
878 advance_route(cur_route, *start->block->get_endpoints()[start->entry].track);
880 float approach_margin = 50*layout.get_catalogue().get_scale();
881 float min_dist = controller->get_braking_distance()*1.3+approach_margin*2;
883 BlockRef *last = start;
884 BlockRef *good = start;
885 Track *divert_track = 0;
886 bool try_divert = false;
887 unsigned good_sens = nsens;
888 float good_dist = dist;
889 Train *blocking_train = 0;
890 std::list<BlockRef> contested_blocks;
892 SetFlag setf(reserving);
894 while(good_sens<3 || good_dist<min_dist || !contested_blocks.empty())
896 // Traverse to the next block
900 const Route *route = (cur_route!=routes.end() ? cur_route->route : 0);
901 unsigned exit = last->block->traverse(last->entry, route, &length);
902 link = last->block->get_link(exit);
907 int entry = link->get_endpoint_by_link(*last->block);
909 throw LogicError("Block links are inconsistent!");
911 const Block::Endpoint &entry_ep = link->get_endpoints()[entry];
913 if(cur_route!=routes.end())
915 if(!advance_route(cur_route, *entry_ep.track))
917 // Keep the blocks if we arrived at the end of the route
928 else if(!routes.empty() && routes.front().route->get_tracks().count(entry_ep.track))
929 cur_route = routes.begin();
931 if(link->get_endpoints().size()<2)
944 if(link->get_train()!=blocking_train)
946 if(blocking_train->free_block(*contested_blocks.back().block))
948 // Roll back and start actually reserving the blocks
949 last = &rsv_blocks.back();
950 cur_route = routes.begin();
951 advance_route(cur_route, *last->block->get_endpoints()[last->entry].track);
952 if(blocking_train->get_priority()==priority)
953 blocking_train->yield_to(*this);
959 yield_to(*blocking_train);
960 pending_block = contested_blocks.front().block;
961 try_divert = divert_track;
967 contested_blocks.push_back(BlockRef(link, entry));
968 last = &contested_blocks.back();
973 bool reserved = link->reserve(this);
976 /* We've found another train. If it wants to exit the block from the
977 same endpoint we're trying to enter from or the other way around,
978 treat it as coming towards us. Otherwise treat it as going in the
980 Train *other_train = link->get_train();
981 int other_entry = other_train->get_entry_to_block(*link);
983 throw LogicError("Block reservation inconsistency");
985 bool entry_conflict = (static_cast<unsigned>(entry)==link->traverse(other_entry));
986 bool exit_conflict = (link->traverse(entry)==static_cast<unsigned>(other_entry));
987 if(!entry_conflict && !last->block->get_turnout_id())
989 /* The other train is not coming to the blocks we're holding, so we
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(*link))
1003 reserved = link->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(BlockRef(link, entry));
1012 last = &contested_blocks.back();
1015 else if(divert_track && (entry_conflict || exit_conflict))
1016 // We are blocked, but there's a diversion possibility
1021 pending_block = link;
1026 if(link->get_turnout_id())
1028 const Endpoint &track_ep = entry_ep.track->get_type().get_endpoints()[entry_ep.track_ep];
1029 bool multiple_paths = (track_ep.paths&(track_ep.paths-1));
1031 if(multiple_paths || !last->block->get_turnout_id())
1033 /* We can keep the blocks reserved so far if we are facing the
1034 points or if there was no turnout immediately before this one.
1035 With multiple successive turnouts (as is common in crossovers) it's
1036 best to hold at one we can divert from. */
1042 // Figure out what path we'd like to take on the turnout
1044 for(list<RouteRef>::iterator i=cur_route; (path<0 && i!=routes.end()); ++i)
1045 path = i->route->get_turnout(link->get_turnout_id());
1047 path = entry_ep.track->get_active_path();
1048 if(!(track_ep.paths&(1<<path)))
1050 for(unsigned i=0; track_ep.paths>>i; ++i)
1051 if(track_ep.paths&(1<<i))
1055 if(path!=static_cast<int>(entry_ep.track->get_active_path()))
1057 // The turnout is set to wrong path - switch and wait for it
1058 pending_block = link;
1059 entry_ep.track->set_active_path(path);
1067 if(multiple_paths && cur_route!=routes.end() && cur_route->diversion!=link->get_turnout_id())
1068 /* There's multiple paths to be taken and we are on a route - take
1069 note of the diversion possibility */
1070 divert_track = entry_ep.track;
1073 if(!contested_blocks.empty() && contested_blocks.front().block==link)
1074 contested_blocks.pop_front();
1076 rsv_blocks.push_back(BlockRef(link, entry));
1077 last = &rsv_blocks.back();
1078 if(last->block->get_sensor_id())
1084 // Unreserve blocks that were not good
1085 while(!rsv_blocks.empty() && &rsv_blocks.back()!=good)
1087 rsv_blocks.back().block->reserve(0);
1088 rsv_blocks.pop_back();
1091 if(!rsv_blocks.empty() && &rsv_blocks.back()!=start)
1092 // We got some new blocks, so no longer need to yield
1095 // Make any sensorless blocks at the beginning immediately current
1096 list<BlockRef>::iterator i;
1097 for(i=rsv_blocks.begin(); (i!=rsv_blocks.end() && !i->block->get_sensor_id()); ++i) ;
1098 if(i!=rsv_blocks.begin())
1099 cur_blocks.splice(cur_blocks.end(), rsv_blocks, rsv_blocks.begin(), i);
1101 if(try_divert && divert(*divert_track))
1102 return reserve_more();
1107 float Train::get_reserved_distance_until(const Block *until_block, bool back) const
1109 if(cur_blocks.empty())
1112 Vehicle &veh = *(reverse!=back ? vehicles.back() : vehicles.front());
1113 const VehicleType &vtype = veh.get_type();
1115 Track *track = veh.get_track();
1119 list<BlockRef>::const_iterator block = cur_blocks.begin();
1120 while(block!=rsv_blocks.end() && !block->block->get_tracks().count(track))
1123 if(block==cur_blocks.end())
1127 block = rsv_blocks.begin();
1130 if(block==rsv_blocks.end() || block->block==until_block)
1133 unsigned entry = veh.get_entry();
1135 float result = veh.get_offset();
1137 entry = track->traverse(entry);
1139 result = track->get_type().get_path_length(track->get_active_path())-result;
1140 result -= vtype.get_length()/2;
1144 if(track->get_type().get_endpoints().size()<2)
1147 Track *next = track->get_link(track->traverse(entry));
1149 if(!block->block->get_tracks().count(next))
1153 if(block==cur_blocks.begin())
1160 if(block==cur_blocks.end())
1161 block = rsv_blocks.begin();
1162 if(block==rsv_blocks.end())
1166 if(block->block==until_block)
1170 entry = next->get_endpoint_by_link(*track);
1173 result += track->get_type().get_path_length(track->get_active_path());
1179 float Train::get_real_speed(unsigned i) const
1181 if(real_speed[i].weight)
1182 return real_speed[i].speed;
1186 for(low=i; low>0; --low)
1187 if(real_speed[low].weight)
1189 for(high=i; high<14; ++high)
1190 if(real_speed[high].weight)
1193 if(real_speed[high].weight)
1195 if(real_speed[low].weight)
1197 float f = float(i-low)/(high-low);
1198 return real_speed[low].speed*(1-f)+real_speed[high].speed*f;
1201 return real_speed[high].speed*float(i)/high;
1203 else if(real_speed[low].weight)
1204 return real_speed[low].speed*float(i)/low;
1209 unsigned Train::find_speed(float real) const
1211 if(real<=real_speed[0].speed)
1217 for(unsigned i=0; (!high && i<=14); ++i)
1218 if(real_speed[i].weight)
1221 if(real_speed[i].speed<real)
1235 return min(min(static_cast<unsigned>(low*real/real_speed[low].speed), 14U), last+3);
1238 float f = (real-real_speed[low].speed)/(real_speed[high].speed-real_speed[low].speed);
1239 return static_cast<unsigned>(low*(1-f)+high*f+0.5);
1242 float Train::get_travel_speed() const
1244 float speed = get_real_speed(current_speed);
1245 float scale = layout.get_catalogue().get_scale();
1246 return static_cast<int>(round(speed/scale*3.6/5))*5;
1249 void Train::set_status(const string &s)
1252 signal_status_changed.emit(s);
1255 void Train::release_blocks(list<BlockRef> &blocks)
1257 release_blocks(blocks, blocks.begin(), blocks.end());
1260 void Train::release_blocks(list<BlockRef> &blocks, list<BlockRef>::iterator begin, list<BlockRef>::iterator end)
1264 Block *block = begin->block;
1265 blocks.erase(begin++);
1270 void Train::reverse_blocks(list<BlockRef> &blocks) const
1273 for(list<BlockRef>::iterator i=blocks.begin(); i!=blocks.end(); ++i)
1274 i->entry = i->block->traverse(i->entry);
1277 bool Train::advance_route(list<RouteRef>::iterator &iter, Track &track)
1279 while(iter!=routes.end() && !iter->route->get_tracks().count(&track))
1281 if(iter==routes.end())
1284 list<RouteRef>::iterator next = iter;
1286 if(next!=routes.end() && next->diversion && next->route->get_tracks().count(&track))
1292 Route *Train::create_lead_route(Route *lead, const Route *target)
1296 lead = new Route(layout);
1297 lead->set_name("Lead");
1298 lead->set_temporary(true);
1301 set<Track *> tracks;
1302 for(list<BlockRef>::iterator i=cur_blocks.begin(); i!=rsv_blocks.end(); )
1304 const set<Track *> &btracks = i->block->get_tracks();
1305 for(set<Track *>::const_iterator j=btracks.begin(); j!=btracks.end(); ++j)
1306 if(!target || !target->get_tracks().count(*j))
1309 if(++i==cur_blocks.end())
1310 i = rsv_blocks.begin();
1313 lead->add_tracks(tracks);
1318 bool Train::is_valid_diversion(const Route &diversion, Track &from, unsigned from_ep)
1320 float diversion_len = 0;
1321 Track *track = &from;
1322 unsigned ep = from_ep;
1323 while(diversion.get_tracks().count(track))
1326 if(track->get_turnout_id())
1327 path = diversion.get_turnout(track->get_turnout_id());
1328 diversion_len += track->get_type().get_path_length(path);
1330 Track *next = track->get_link(track->traverse(ep, path));
1331 ep = next->get_endpoint_by_link(*track);
1338 list<RouteRef>::iterator route = routes.begin();
1339 if(!advance_route(route, from))
1342 set<Track *> visited;
1343 float route_len = 0;
1349 if(track->get_turnout_id())
1350 path = route->route->get_turnout(track->get_turnout_id());
1351 route_len += track->get_type().get_path_length(path);
1353 if(track!=&from && diversion.get_tracks().count(track))
1356 if(visited.count(track))
1358 visited.insert(track);
1360 Track *next = track->get_link(track->traverse(ep, path));
1361 ep = next->get_endpoint_by_link(*track);
1364 if(!advance_route(route, *track))
1368 return diversion_len<route_len*1.2;
1372 Train::BlockRef::BlockRef(Block *b, unsigned e):
1377 Train::BlockRef Train::BlockRef::next() const
1379 Block *blk = block->get_endpoints()[block->traverse(entry)].link;
1381 throw InvalidState("At end of line");
1383 int ep = blk->get_endpoint_by_link(*block);
1385 throw LogicError("Block links are inconsistent");
1387 return BlockRef(blk, ep);
1391 Train::RouteRef::RouteRef(const Route *r, unsigned d):
1397 Train::RealSpeed::RealSpeed():
1402 void Train::RealSpeed::add(float s, float w)
1404 speed = (speed*weight+s*w)/(weight+w);
1405 weight = min(weight+w, 300.0f);
1409 Train::Loader::Loader(Train &t):
1410 DataFile::BasicLoader<Train>(t),
1414 add("block", &Loader::block);
1415 add("block_hint", &Loader::block_hint);
1416 add("name", &Loader::name);
1417 add("priority", &Train::priority);
1418 add("real_speed", &Loader::real_speed);
1419 add("route", &Loader::route);
1420 add("timetable", &Loader::timetable);
1421 add("vehicle", &Loader::vehicle);
1424 void Train::Loader::finish()
1426 if(!obj.cur_blocks.empty())
1428 const BlockRef &blkref = obj.cur_blocks.front();
1429 const Block::Endpoint &bep = blkref.block->get_endpoints()[blkref.entry];
1430 float offset = 2*obj.layout.get_catalogue().get_scale();
1431 obj.vehicles.back()->place(*bep.track, bep.track_ep, offset, Vehicle::BACK_BUFFER);
1433 obj.set_status("Stopped");
1437 void Train::Loader::block(unsigned id)
1445 blk = &obj.layout.get_block(id);
1447 catch(const KeyError &)
1449 blocks_valid = false;
1455 entry = blk->get_endpoint_by_link(*prev_block);
1460 obj.cur_blocks.push_back(BlockRef(blk, entry));
1462 if(blk->get_sensor_id())
1463 obj.layout.get_driver().set_sensor(blk->get_sensor_id(), true);
1468 void Train::Loader::block_hint(unsigned id)
1472 prev_block = &obj.layout.get_block(id);
1474 catch(const KeyError &)
1476 blocks_valid = false;
1480 void Train::Loader::name(const string &n)
1485 void Train::Loader::real_speed(unsigned i, float speed, float weight)
1487 obj.real_speed[i].speed = speed;
1488 obj.real_speed[i].weight = weight;
1491 void Train::Loader::route(const string &n)
1493 obj.set_route(&obj.layout.get_route(n));
1496 void Train::Loader::timetable()
1499 throw InvalidState("A timetable has already been loaded");
1501 obj.timetable = new Timetable(obj);
1502 load_sub(*obj.timetable);
1505 void Train::Loader::vehicle(unsigned n)
1507 const VehicleType &vtype = obj.layout.get_catalogue().get_vehicle(n);
1508 Vehicle *veh = new Vehicle(obj.layout, vtype);
1509 obj.vehicles.back()->attach_back(*veh);
1510 obj.vehicles.push_back(veh);
1513 } // namespace Marklin