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 &last = (rsv_blocks.empty() ? cur_blocks.back() : rsv_blocks.back());
218 BlockRef next = last.next();
219 const Block::Endpoint &ep = next.block->get_endpoints()[next.entry];
220 if(!r->get_tracks().count(ep.track))
221 routes.push_front(Route::find(*ep.track, ep.track_ep, *r));
223 /* XXX This is sort of a hack, but it keeps divert() happy. Need to come
224 up with a better solution when there is time. */
225 routes.push_front(create_lead_route());
230 signal_route_changed.emit(get_route());
233 void Train::go_to(const Track &to)
235 for(list<BlockRef>::const_iterator i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
236 if(i->block->get_tracks().count(const_cast<Track *>(&to)))
238 signal_arrived.emit();
243 free_noncritical_blocks();
245 BlockRef &last = (rsv_blocks.empty() ? cur_blocks.back() : rsv_blocks.back());
246 BlockRef next = last.next();
247 const Block::Endpoint &ep = next.block->get_endpoints()[next.entry];
249 set_route(Route::find(*ep.track, ep.track_ep, to));
252 bool Train::divert(Track &from)
254 if(!from.get_turnout_id())
255 throw InvalidParameterValue("Can't divert from a non-turnout");
260 unsigned from_ep = 0;
261 list<RouteRef>::iterator route = routes.begin();
262 Block *block = cur_blocks.back().block;
263 unsigned entry = cur_blocks.back().entry;
264 set<const Track *> visited;
266 // Follow our routes to find out where we're entering the turnout
269 Block *link = block->get_link(block->traverse(entry, route->route));
270 entry = link->get_endpoint_by_link(*block);
273 const Block::Endpoint &entry_ep = block->get_endpoints()[entry];
275 if(visited.count(entry_ep.track))
277 visited.insert(entry_ep.track);
279 if(!advance_route(route, *entry_ep.track))
282 if(entry_ep.track==&from)
284 if(block->get_train()==this && !free_block(*block))
287 from_ep = entry_ep.track_ep;
288 path = route->route->get_turnout(from.get_turnout_id());
293 // Check that more than one path is available
294 unsigned ep_paths = from.get_type().get_endpoints()[from_ep].paths;
295 if(!(ep_paths&(ep_paths-1)))
298 // Choose some other path
299 for(int i=0; ep_paths>>i; ++i)
300 if((ep_paths&(1<<i)) && i!=path)
306 Track *track = from.get_link(from.traverse(from_ep, path));
310 unsigned ep = track->get_endpoint_by_link(from);
312 set<const Track *> tracks;
313 for(list<RouteRef>::iterator i=routes.begin(); i!=routes.end(); ++i)
314 tracks.insert(i->route->get_tracks().begin(), i->route->get_tracks().end());
315 Route *diversion = 0;
318 diversion = Route::find(*track, ep, tracks);
320 catch(const Msp::Exception &)
325 diversion->set_name("Diversion");
326 diversion->add_track(from);
327 diversion->set_turnout(from.get_turnout_id(), path);
329 if(!is_valid_diversion(*diversion, from, from_ep))
335 // Follow the diversion route until we get back to the original route
336 list<RouteRef>::iterator end = routes.end();
340 if(track->get_turnout_id())
341 path = diversion->get_turnout(track->get_turnout_id());
342 Track *next = track->get_link(track->traverse(ep, path));
344 for(list<RouteRef>::iterator i=route; (end==routes.end() && i!=routes.end()); ++i)
345 if(i->route->get_tracks().count(next))
348 if(end!=routes.end())
350 else if(!diversion->get_tracks().count(next))
351 throw Exception("Pathfinder returned a bad route");
353 ep = next->get_endpoint_by_link(*track);
358 // We are rejoining the same route we diverted from, duplicate it
359 routes.insert(end, *route);
363 routes.erase(route, end);
365 routes.insert(end, RouteRef(diversion, from.get_turnout_id()));
370 const Route *Train::get_route() const
374 return routes.front().route;
377 void Train::place(Block &block, unsigned entry)
379 if(controller->get_speed())
380 throw InvalidState("Must be stopped before placing");
382 release_blocks(rsv_blocks);
383 release_blocks(cur_blocks);
386 accurate_position = false;
388 if(!block.reserve(this))
390 set_status("Unplaced");
394 cur_blocks.push_back(BlockRef(&block, entry));
397 unsigned exit = block.traverse(entry);
398 const Block::Endpoint &bep = block.get_endpoints()[exit];
399 Track *track = bep.track->get_link(bep.track_ep);
400 unsigned ep = track->get_endpoint_by_link(*bep.track);
401 vehicles.front()->place(*track, ep, 0, Vehicle::FRONT_BUFFER);
405 const Block::Endpoint &bep = block.get_endpoints()[entry];
406 vehicles.back()->place(*bep.track, bep.track_ep, 0, Vehicle::BACK_BUFFER);
410 void Train::unplace()
412 if(controller->get_speed())
413 throw InvalidState("Must be stopped before unplacing");
415 release_blocks(rsv_blocks);
416 release_blocks(cur_blocks);
419 accurate_position = false;
421 for(vector<Vehicle *>::iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
424 set_status("Unplaced");
427 bool Train::free_block(Block &block)
429 float margin = 10*layout.get_catalogue().get_scale();
430 if(get_reserved_distance_until(&block, false)<controller->get_braking_distance()*1.3+margin)
434 for(list<BlockRef>::iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
440 release_blocks(rsv_blocks, i, rsv_blocks.end());
443 else if(i->block->get_sensor_id())
450 void Train::free_noncritical_blocks()
452 if(cur_blocks.empty() || rsv_blocks.empty())
455 if(controller->get_speed()==0)
457 release_blocks(rsv_blocks);
461 float margin = 10*layout.get_catalogue().get_scale();
462 float min_dist = controller->get_braking_distance()*1.3+margin;
464 Vehicle &veh = *(reverse ? vehicles.back() : vehicles.front());
466 Track *track = veh.get_track();
467 list<BlockRef>::iterator block = cur_blocks.begin();
469 while(block!=rsv_blocks.end() && !block->block->get_tracks().count(track))
472 if(block==cur_blocks.end())
474 block = rsv_blocks.begin();
479 unsigned entry = veh.get_entry();
480 float dist = veh.get_offset();
482 entry = track->traverse(entry);
484 dist = track->get_type().get_path_length(track->get_active_path())-dist;
485 dist -= veh.get_type().get_length()/2;
490 Track *next = track->get_link(track->traverse(entry));
491 entry = next->get_endpoint_by_link(*track);
494 if(!block->block->get_tracks().count(track))
497 if(block==cur_blocks.end())
499 block = rsv_blocks.begin();
502 if(block==rsv_blocks.end())
505 if(dist>min_dist && nsens>0)
507 release_blocks(rsv_blocks, block, rsv_blocks.end());
511 if(in_rsv && block->block->get_sensor_id())
515 dist += track->get_type().get_path_length(track->get_active_path());
519 int Train::get_entry_to_block(Block &block) const
521 for(list<BlockRef>::const_iterator i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
524 for(list<BlockRef>::const_iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
530 float Train::get_reserved_distance() const
532 return get_reserved_distance_until(0, false);
535 void Train::tick(const Time::TimeStamp &t, const Time::TimeDelta &dt)
537 if(!active && stop_timeout && t>=stop_timeout)
539 release_blocks(rsv_blocks);
540 end_of_route = false;
541 stop_timeout = Time::TimeStamp();
544 Driver &driver = layout.get_driver();
548 controller->tick(dt);
549 float speed = controller->get_speed();
550 unsigned speed_notch = find_speed(speed);
552 if(controller->get_reverse()!=reverse)
554 reverse = controller->get_reverse();
555 driver.set_loco_reverse(address, reverse);
557 release_blocks(rsv_blocks);
558 reverse_blocks(cur_blocks);
562 if(speed_notch!=current_speed && !speed_changing && !driver.is_halted() && driver.get_power())
564 speed_changing = true;
565 driver.set_loco_speed(address, speed_notch);
570 set_status(format("Traveling %d kmh", get_travel_speed()));
572 set_status("Waiting");
580 Vehicle &vehicle = *(reverse ? vehicles.back() : vehicles.front());
581 Track *track = vehicle.get_track();
584 for(list<BlockRef>::const_iterator i=cur_blocks.begin(); (!ok && i!=cur_blocks.end()); ++i)
585 ok = i->block->get_tracks().count(track);
587 float d = get_real_speed(current_speed)*(dt/Time::sec);
590 SetFlag setf(advancing);
591 vehicle.advance(reverse ? -d : d);
593 else if(accurate_position)
596 if(overshoot_dist>40*layout.get_catalogue().get_scale())
598 layout.emergency(name+" has not arrived at sensor");
599 accurate_position = false;
603 else if(end_of_route && rsv_blocks.empty())
606 signal_arrived.emit();
610 if(!cur_blocks.empty() && !cur_blocks.front().block->get_sensor_id())
612 float dist = get_reserved_distance_until(cur_blocks.front().block, true);
614 if(dist>10*layout.get_catalogue().get_scale())
616 cur_blocks.front().block->reserve(0);
617 cur_blocks.pop_front();
622 void Train::save(list<DataFile::Statement> &st) const
624 st.push_back((DataFile::Statement("name"), name));
626 st.push_back((DataFile::Statement("priority"), priority));
628 for(vector<Vehicle *>::const_iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
629 if(i!=vehicles.begin())
630 st.push_back((DataFile::Statement("vehicle"), (*i)->get_type().get_article_number()));
632 for(unsigned i=0; i<=14; ++i)
633 if(real_speed[i].weight)
634 st.push_back((DataFile::Statement("real_speed"), i, real_speed[i].speed, real_speed[i].weight));
636 if(!cur_blocks.empty())
638 list<BlockRef> blocks = cur_blocks;
640 reverse_blocks(blocks);
642 Block *prev = blocks.front().block->get_endpoints()[blocks.front().entry].link;
643 st.push_back((DataFile::Statement("block_hint"), prev->get_id()));
645 for(list<BlockRef>::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
646 st.push_back((DataFile::Statement("block"), i->block->get_id()));
651 list<RouteRef>::const_iterator i = routes.begin();
652 for(; (i!=routes.end() && i->route->is_temporary()); ++i) ;
654 st.push_back((DataFile::Statement("route"), i->route->get_name()));
659 DataFile::Statement ss("timetable");
660 timetable->save(ss.sub);
665 void Train::control_changed(const Controller::Control &ctrl)
667 signal_control_changed.emit(ctrl.name, ctrl.value);
670 void Train::loco_speed_event(unsigned addr, unsigned speed, bool)
674 current_speed = speed;
675 speed_changing = false;
680 void Train::loco_func_event(unsigned addr, unsigned func, bool state)
682 if(addr==address || (addr==address+1 && loco_type.get_max_function()>4))
687 functions |= 1<<func;
689 functions &= ~(1<<func);
691 signal_function_changed.emit(func, state);
695 void Train::sensor_event(unsigned addr, bool state)
699 // Find the first sensor block from our reserved blocks that isn't this sensor
700 list<BlockRef>::iterator i;
702 for(i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
703 if(i->block->get_sensor_id())
705 if(i->block->get_sensor_id()!=addr)
718 if(result==1 && i!=rsv_blocks.begin())
720 // Compute speed and update related state
721 float travel_time_secs = (Time::now()-last_entry_time)/Time::sec;
727 RealSpeed &rs = real_speed[current_speed];
728 rs.add(travel_dist/travel_time_secs, travel_time_secs);
730 set_status(format("Traveling %d kmh", get_travel_speed()));
735 for(list<BlockRef>::iterator j=rsv_blocks.begin(); j!=i; ++j)
737 j->block->traverse(j->entry, &block_len);
738 travel_dist += block_len;
740 if(j->block->get_sensor_id()==addr && !advancing)
742 const Block::Endpoint &bep = j->block->get_endpoints()[j->entry];
745 Track *track = bep.track->get_link(bep.track_ep);
746 unsigned ep = track->get_endpoint_by_link(*bep.track);
747 vehicles.back()->place(*track, ep, 0, Vehicle::BACK_AXLE);
750 vehicles.front()->place(*bep.track, bep.track_ep, 0, Vehicle::FRONT_AXLE);
753 last_entry_time = Time::now();
755 accurate_position = true;
758 // Check if we've reached the next route
761 const set<const Track *> &rtracks = (++routes.begin())->route->get_tracks();
762 for(list<BlockRef>::iterator j=rsv_blocks.begin(); j!=i; ++j)
763 if(rtracks.count(j->block->get_endpoints()[j->entry].track))
767 signal_route_changed.emit(routes.front().route);
772 // Move blocks up to the next sensor to our current blocks
773 cur_blocks.splice(cur_blocks.end(), rsv_blocks, rsv_blocks.begin(), i);
775 // Try to get more blocks if we're moving
780 layout.emergency("Sensor for "+name+" triggered out of order");
784 const Vehicle &veh = *(reverse ? vehicles.front() : vehicles.back());
786 // Find the first sensor in our current blocks that's still active
787 list<BlockRef>::iterator end = cur_blocks.begin();
788 for(list<BlockRef>::iterator i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
790 if(i->block->get_tracks().count(veh.get_track()))
792 if(i->block->get_sensor_id())
794 if(layout.get_driver().get_sensor(i->block->get_sensor_id()))
804 if(end!=cur_blocks.begin() && end!=cur_blocks.end())
805 // Free blocks up to the last inactive sensor
806 release_blocks(cur_blocks, cur_blocks.begin(), end);
810 void Train::turnout_event(unsigned addr, bool)
812 if(pending_block && (!pending_block->get_train() || pending_block->get_train()==this))
814 unsigned pending_addr = pending_block->get_turnout_id();
815 bool double_addr = (*pending_block->get_tracks().begin())->get_type().is_double_address();
816 if(addr==pending_addr || (double_addr && addr==pending_addr+1))
826 void Train::halt_event(bool h)
829 accurate_position = false;
832 void Train::block_reserved(const Block &block, const Train *train)
834 if(&block==pending_block && !train && !reserving)
838 unsigned Train::reserve_more()
844 if(!rsv_blocks.empty())
845 start = &rsv_blocks.back();
846 else if(!cur_blocks.empty())
847 start = &cur_blocks.back();
853 // See how many sensor blocks and how much track we already have
856 for(list<BlockRef>::const_iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
858 if(i->block->get_sensor_id())
863 i->block->traverse(i->entry, &length);
871 list<RouteRef>::iterator cur_route = routes.begin();
872 advance_route(cur_route, *start->block->get_endpoints()[start->entry].track);
874 float approach_margin = 50*layout.get_catalogue().get_scale();
875 float min_dist = controller->get_braking_distance()*1.3+approach_margin*2;
877 BlockRef *last = start;
878 BlockRef *good = start;
879 Track *divert_track = 0;
880 bool try_divert = false;
881 unsigned good_sens = nsens;
882 float good_dist = dist;
883 Train *blocking_train = 0;
884 std::list<BlockRef> contested_blocks;
886 SetFlag setf(reserving);
888 while(good_sens<3 || good_dist<min_dist || !contested_blocks.empty())
890 // Traverse to the next block
894 const Route *route = (cur_route!=routes.end() ? cur_route->route : 0);
895 unsigned exit = last->block->traverse(last->entry, route, &length);
896 link = last->block->get_link(exit);
901 int entry = link->get_endpoint_by_link(*last->block);
903 throw LogicError("Block links are inconsistent!");
905 const Block::Endpoint &entry_ep = link->get_endpoints()[entry];
907 if(cur_route!=routes.end())
909 if(!advance_route(cur_route, *entry_ep.track))
911 // Keep the blocks if we arrived at the end of the route
922 else if(!routes.empty() && routes.front().route->get_tracks().count(entry_ep.track))
923 cur_route = routes.begin();
925 if(link->get_endpoints().size()<2)
938 if(link->get_train()!=blocking_train)
940 if(blocking_train->free_block(*contested_blocks.back().block))
942 // Roll back and start actually reserving the blocks
943 last = &rsv_blocks.back();
944 cur_route = routes.begin();
945 advance_route(cur_route, *last->block->get_endpoints()[last->entry].track);
946 if(blocking_train->get_priority()==priority)
947 blocking_train->yield_to(*this);
953 yield_to(*blocking_train);
954 pending_block = contested_blocks.front().block;
955 try_divert = divert_track;
961 contested_blocks.push_back(BlockRef(link, entry));
962 last = &contested_blocks.back();
967 bool reserved = link->reserve(this);
970 /* We've found another train. If it wants to exit the block from the
971 same endpoint we're trying to enter from or the other way around,
972 treat it as coming towards us. Otherwise treat it as going in the
974 Train *other_train = link->get_train();
975 int other_entry = other_train->get_entry_to_block(*link);
977 throw LogicError("Block reservation inconsistency");
979 bool entry_conflict = (static_cast<unsigned>(entry)==link->traverse(other_entry));
980 bool exit_conflict = (link->traverse(entry)==static_cast<unsigned>(other_entry));
981 if(!entry_conflict && !last->block->get_turnout_id())
983 /* The other train is not coming to the blocks we're holding, so we
990 int other_prio = other_train->get_priority();
992 if(!entry_conflict && !exit_conflict && other_prio<priority)
994 /* Ask a lesser priority train going to the same direction to free
996 if(other_train->free_block(*link))
997 reserved = link->reserve(this);
999 else if(other_train!=yielding_to && (other_prio<priority || (other_prio==priority && entry_conflict)))
1001 /* A lesser priority train is coming at us, we must ask it to free
1002 enough blocks to get clear of it to avoid a potential deadlock */
1003 blocking_train = other_train;
1004 contested_blocks.clear();
1005 contested_blocks.push_back(BlockRef(link, entry));
1006 last = &contested_blocks.back();
1009 else if(divert_track && (entry_conflict || exit_conflict))
1010 // We are blocked, but there's a diversion possibility
1015 pending_block = link;
1020 if(link->get_turnout_id())
1022 const Endpoint &track_ep = entry_ep.track->get_type().get_endpoints()[entry_ep.track_ep];
1023 bool multiple_paths = (track_ep.paths&(track_ep.paths-1));
1025 if(multiple_paths || !last->block->get_turnout_id())
1027 /* We can keep the blocks reserved so far if we are facing the
1028 points or if there was no turnout immediately before this one.
1029 With multiple successive turnouts (as is common in crossovers) it's
1030 best to hold at one we can divert from. */
1036 // Figure out what path we'd like to take on the turnout
1038 for(list<RouteRef>::iterator i=cur_route; (path<0 && i!=routes.end()); ++i)
1039 path = i->route->get_turnout(link->get_turnout_id());
1041 path = entry_ep.track->get_active_path();
1042 if(!(track_ep.paths&(1<<path)))
1044 for(unsigned i=0; track_ep.paths>>i; ++i)
1045 if(track_ep.paths&(1<<i))
1049 if(path!=static_cast<int>(entry_ep.track->get_active_path()))
1051 // The turnout is set to wrong path - switch and wait for it
1052 pending_block = link;
1053 entry_ep.track->set_active_path(path);
1061 if(multiple_paths && cur_route!=routes.end() && cur_route->diversion!=link->get_turnout_id())
1062 /* There's multiple paths to be taken and we are on a route - take
1063 note of the diversion possibility */
1064 divert_track = entry_ep.track;
1067 if(!contested_blocks.empty() && contested_blocks.front().block==link)
1068 contested_blocks.pop_front();
1070 rsv_blocks.push_back(BlockRef(link, entry));
1071 last = &rsv_blocks.back();
1072 if(last->block->get_sensor_id())
1078 // Unreserve blocks that were not good
1079 while(!rsv_blocks.empty() && &rsv_blocks.back()!=good)
1081 rsv_blocks.back().block->reserve(0);
1082 rsv_blocks.pop_back();
1085 if(!rsv_blocks.empty() && &rsv_blocks.back()!=start)
1086 // We got some new blocks, so no longer need to yield
1089 // Make any sensorless blocks at the beginning immediately current
1090 list<BlockRef>::iterator i;
1091 for(i=rsv_blocks.begin(); (i!=rsv_blocks.end() && !i->block->get_sensor_id()); ++i) ;
1092 if(i!=rsv_blocks.begin())
1093 cur_blocks.splice(cur_blocks.end(), rsv_blocks, rsv_blocks.begin(), i);
1095 if(try_divert && divert(*divert_track))
1096 return reserve_more();
1101 float Train::get_reserved_distance_until(const Block *until_block, bool back) const
1103 if(cur_blocks.empty())
1106 Vehicle &veh = *(reverse!=back ? vehicles.back() : vehicles.front());
1107 const VehicleType &vtype = veh.get_type();
1109 Track *track = veh.get_track();
1113 list<BlockRef>::const_iterator block = cur_blocks.begin();
1114 while(block!=rsv_blocks.end() && !block->block->get_tracks().count(track))
1117 if(block==cur_blocks.end())
1121 block = rsv_blocks.begin();
1124 if(block==rsv_blocks.end() || block->block==until_block)
1127 unsigned entry = veh.get_entry();
1129 float result = veh.get_offset();
1131 entry = track->traverse(entry);
1133 result = track->get_type().get_path_length(track->get_active_path())-result;
1134 result -= vtype.get_length()/2;
1138 if(track->get_type().get_endpoints().size()<2)
1141 Track *next = track->get_link(track->traverse(entry));
1143 if(!block->block->get_tracks().count(next))
1147 if(block==cur_blocks.begin())
1154 if(block==cur_blocks.end())
1155 block = rsv_blocks.begin();
1156 if(block==rsv_blocks.end())
1160 if(block->block==until_block)
1164 entry = next->get_endpoint_by_link(*track);
1167 result += track->get_type().get_path_length(track->get_active_path());
1173 float Train::get_real_speed(unsigned i) const
1175 if(real_speed[i].weight)
1176 return real_speed[i].speed;
1180 for(low=i; low>0; --low)
1181 if(real_speed[low].weight)
1183 for(high=i; high<14; ++high)
1184 if(real_speed[high].weight)
1187 if(real_speed[high].weight)
1189 if(real_speed[low].weight)
1191 float f = float(i-low)/(high-low);
1192 return real_speed[low].speed*(1-f)+real_speed[high].speed*f;
1195 return real_speed[high].speed*float(i)/high;
1197 else if(real_speed[low].weight)
1198 return real_speed[low].speed*float(i)/low;
1203 unsigned Train::find_speed(float real) const
1205 if(real<=real_speed[0].speed)
1211 for(unsigned i=0; (!high && i<=14); ++i)
1212 if(real_speed[i].weight)
1215 if(real_speed[i].speed<real)
1229 return min(min(static_cast<unsigned>(low*real/real_speed[low].speed), 14U), last+3);
1232 float f = (real-real_speed[low].speed)/(real_speed[high].speed-real_speed[low].speed);
1233 return static_cast<unsigned>(low*(1-f)+high*f+0.5);
1236 float Train::get_travel_speed() const
1238 float speed = get_real_speed(current_speed);
1239 float scale = layout.get_catalogue().get_scale();
1240 return static_cast<int>(round(speed/scale*3.6/5))*5;
1243 void Train::set_status(const string &s)
1246 signal_status_changed.emit(s);
1249 void Train::release_blocks(list<BlockRef> &blocks)
1251 release_blocks(blocks, blocks.begin(), blocks.end());
1254 void Train::release_blocks(list<BlockRef> &blocks, list<BlockRef>::iterator begin, list<BlockRef>::iterator end)
1258 Block *block = begin->block;
1259 blocks.erase(begin++);
1264 void Train::reverse_blocks(list<BlockRef> &blocks) const
1267 for(list<BlockRef>::iterator i=blocks.begin(); i!=blocks.end(); ++i)
1268 i->entry = i->block->traverse(i->entry);
1271 bool Train::advance_route(list<RouteRef>::iterator &iter, const Track &track)
1273 while(iter!=routes.end() && !iter->route->get_tracks().count(&track))
1275 if(iter==routes.end())
1278 list<RouteRef>::iterator next = iter;
1280 if(next!=routes.end() && next->diversion && next->route->get_tracks().count(&track))
1286 Route *Train::create_lead_route()
1288 Route *lead = new Route(layout);
1289 lead->set_name("Lead");
1290 lead->set_temporary(true);
1292 for(list<BlockRef>::iterator i=cur_blocks.begin(); i!=rsv_blocks.end(); )
1294 // XXX Make Route eat non-const tracks to get rid of this idiocy and various const_casts
1295 const set<Track *> &btracks = i->block->get_tracks();
1296 set<const Track *> tracks(btracks.begin(), btracks.end());
1297 lead->add_tracks(tracks);
1299 if(++i==cur_blocks.end())
1300 i = rsv_blocks.begin();
1306 bool Train::is_valid_diversion(const Route &diversion, const Track &from, unsigned from_ep)
1308 float diversion_len = 0;
1309 const Track *track = &from;
1310 unsigned ep = from_ep;
1311 while(diversion.get_tracks().count(track))
1314 if(track->get_turnout_id())
1315 path = diversion.get_turnout(track->get_turnout_id());
1316 diversion_len += track->get_type().get_path_length(path);
1318 const Track *next = track->get_link(track->traverse(ep, path));
1319 ep = next->get_endpoint_by_link(*track);
1326 list<RouteRef>::iterator route = routes.begin();
1327 if(!advance_route(route, from))
1330 set<const Track *> visited;
1331 float route_len = 0;
1337 if(track->get_turnout_id())
1338 path = route->route->get_turnout(track->get_turnout_id());
1339 route_len += track->get_type().get_path_length(path);
1341 if(track!=&from && diversion.get_tracks().count(track))
1344 if(visited.count(track))
1346 visited.insert(track);
1348 const Track *next = track->get_link(track->traverse(ep, path));
1349 ep = next->get_endpoint_by_link(*track);
1352 if(!advance_route(route, *track))
1356 return diversion_len<route_len*1.2;
1360 Train::BlockRef::BlockRef(Block *b, unsigned e):
1365 Train::BlockRef Train::BlockRef::next() const
1367 Block *blk = block->get_endpoints()[block->traverse(entry)].link;
1369 throw InvalidState("At end of line");
1371 int ep = blk->get_endpoint_by_link(*block);
1373 throw LogicError("Block links are inconsistent");
1375 return BlockRef(blk, ep);
1379 Train::RouteRef::RouteRef(const Route *r, unsigned d):
1385 Train::RealSpeed::RealSpeed():
1390 void Train::RealSpeed::add(float s, float w)
1392 speed = (speed*weight+s*w)/(weight+w);
1393 weight = min(weight+w, 300.0f);
1397 Train::Loader::Loader(Train &t):
1398 DataFile::BasicLoader<Train>(t),
1402 add("block", &Loader::block);
1403 add("block_hint", &Loader::block_hint);
1404 add("name", &Loader::name);
1405 add("priority", &Train::priority);
1406 add("real_speed", &Loader::real_speed);
1407 add("route", &Loader::route);
1408 add("timetable", &Loader::timetable);
1409 add("vehicle", &Loader::vehicle);
1412 void Train::Loader::finish()
1414 if(!obj.cur_blocks.empty())
1416 const BlockRef &blkref = obj.cur_blocks.front();
1417 const Block::Endpoint &bep = blkref.block->get_endpoints()[blkref.entry];
1418 float offset = 2*obj.layout.get_catalogue().get_scale();
1419 obj.vehicles.back()->place(*bep.track, bep.track_ep, offset, Vehicle::BACK_BUFFER);
1421 obj.set_status("Stopped");
1425 void Train::Loader::block(unsigned id)
1433 blk = &obj.layout.get_block(id);
1435 catch(const KeyError &)
1437 blocks_valid = false;
1443 entry = blk->get_endpoint_by_link(*prev_block);
1448 obj.cur_blocks.push_back(BlockRef(blk, entry));
1450 if(blk->get_sensor_id())
1451 obj.layout.get_driver().set_sensor(blk->get_sensor_id(), true);
1456 void Train::Loader::block_hint(unsigned id)
1460 prev_block = &obj.layout.get_block(id);
1462 catch(const KeyError &)
1464 blocks_valid = false;
1468 void Train::Loader::name(const string &n)
1473 void Train::Loader::real_speed(unsigned i, float speed, float weight)
1475 obj.real_speed[i].speed = speed;
1476 obj.real_speed[i].weight = weight;
1479 void Train::Loader::route(const string &n)
1481 obj.set_route(&obj.layout.get_route(n));
1484 void Train::Loader::timetable()
1487 throw InvalidState("A timetable has already been loaded");
1489 obj.timetable = new Timetable(obj);
1490 load_sub(*obj.timetable);
1493 void Train::Loader::vehicle(unsigned n)
1495 const VehicleType &vtype = obj.layout.get_catalogue().get_vehicle(n);
1496 Vehicle *veh = new Vehicle(obj.layout, vtype);
1497 obj.vehicles.back()->attach_back(*veh);
1498 obj.vehicles.push_back(veh);
1501 } // namespace Marklin