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 "trackiter.h"
20 #include "tracktype.h"
23 #include "vehicletype.h"
34 SetFlag(bool &f): flag(f) { flag = true; }
35 ~SetFlag() { flag = false; }
43 Train::Train(Layout &l, const VehicleType &t, unsigned a, const string &p):
50 cur_blocks_end(blocks.end()),
51 clear_blocks_end(blocks.end()),
55 controller(new AIControl(*this, new SimpleController)),
58 current_speed_step(0),
59 speed_changing(false),
66 real_speed(layout.get_driver().get_protocol_speed_steps(protocol)+1),
67 accurate_position(false),
70 if(!loco_type.is_locomotive())
71 throw InvalidParameterValue("Initial vehicle must be a locomotive");
73 vehicles.push_back(new Vehicle(layout, loco_type));
75 layout.add_train(*this);
77 layout.get_driver().add_loco(address, protocol);
78 layout.get_driver().signal_loco_speed.connect(sigc::mem_fun(this, &Train::loco_speed_event));
79 layout.get_driver().signal_loco_function.connect(sigc::mem_fun(this, &Train::loco_func_event));
81 layout.signal_block_reserved.connect(sigc::mem_fun(this, &Train::block_reserved));
82 layout.get_driver().signal_sensor.connect(sigc::mem_fun(this, &Train::sensor_event));
84 layout.get_driver().signal_halt.connect(sigc::mem_fun(this, &Train::halt_event));
86 const set<Track *> &tracks = layout.get_tracks();
87 for(set<Track *>::const_iterator i=tracks.begin(); i!=tracks.end(); ++i)
88 if((*i)->get_turnout_id())
89 (*i)->signal_path_changed.connect(sigc::hide(sigc::bind(sigc::mem_fun(this, &Train::turnout_path_changed), sigc::ref(**i))));
91 controller->signal_control_changed.connect(sigc::mem_fun(this, &Train::control_changed));
98 for(vector<Vehicle *>::iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
100 layout.remove_train(*this);
103 void Train::set_name(const string &n)
107 signal_name_changed.emit(name);
110 void Train::set_priority(int p)
115 void Train::yield_to(const Train &t)
120 void Train::add_vehicle(const VehicleType &vt)
122 Vehicle *veh = new Vehicle(layout, vt);
123 vehicles.back()->attach_back(*veh);
124 vehicles.push_back(veh);
127 void Train::remove_vehicle(unsigned i)
129 if(i>=vehicles.size())
130 throw InvalidParameterValue("Vehicle index out of range");
132 throw InvalidParameterValue("Can't remove the locomotive");
134 vehicles.erase(vehicles.begin()+i);
135 if(i<vehicles.size())
136 vehicles[i-1]->attach_back(*vehicles[i]);
139 unsigned Train::get_n_vehicles() const
141 return vehicles.size();
144 Vehicle &Train::get_vehicle(unsigned i)
146 if(i>=vehicles.size())
147 throw InvalidParameterValue("Vehicle index out of range");
151 const Vehicle &Train::get_vehicle(unsigned i) const
153 if(i>=vehicles.size())
154 throw InvalidParameterValue("Vehicle index out of range");
158 void Train::set_control(const string &n, float v)
160 controller->set_control(n, v);
163 void Train::set_active(bool a)
167 if(!a && controller->get_speed())
168 throw InvalidState("Can't deactivate while moving");
173 stop_timeout = Time::TimeStamp();
178 stop_timeout = Time::now()+2*Time::sec;
179 set_status("Stopped");
183 void Train::set_function(unsigned func, bool state)
185 if(!loco_type.get_functions().count(func))
186 throw InvalidParameterValue("Invalid function");
188 layout.get_driver().set_loco_function(address, func, state);
190 layout.get_driver().set_loco_function(address+1, func-4, state);
193 float Train::get_control(const string &ctrl) const
195 return controller->get_control(ctrl).value;
198 float Train::get_speed() const
200 return controller->get_speed();
203 bool Train::get_function(unsigned func) const
205 return (functions>>func)&1;
208 void Train::set_timetable(Timetable *tt)
214 bool Train::set_route(const Route *r)
216 free_noncritical_blocks();
219 if(r && !blocks.empty())
221 TrackIter first = blocks.front().track_iter();
222 TrackIter next = blocks.back().next().track_iter();
223 if(!r->has_track(*next))
225 lead = Route::find(next, *r);
228 create_lead_route(lead, lead);
229 routes.push_front(lead);
231 else if(!r->has_track(*first))
232 lead = create_lead_route(0, r);
237 routes.push_back(lead);
240 end_of_route = false;
244 signal_route_changed.emit(get_route());
249 bool Train::go_to(Track &to)
251 for(BlockList::const_iterator i=blocks.begin(); i!=cur_blocks_end; ++i)
252 if((*i)->has_track(to))
254 signal_arrived.emit();
258 free_noncritical_blocks();
260 TrackIter next = blocks.back().next().track_iter();
262 Route *route = Route::find(next, to);
265 create_lead_route(route, route);
266 return set_route(route);
269 bool Train::divert(Track &from)
271 if(!from.get_turnout_id())
272 throw InvalidParameterValue("Can't divert from a non-turnout");
278 list<RouteRef>::iterator route = routes.begin();
280 // Follow our routes to find out where we're entering the turnout
281 for(TrackLoopIter track = blocks.front().track_iter();;)
283 if(!advance_route(route, *track))
288 Block &block = track->get_block();
289 if(block.get_train()==this && !free_block(block))
292 int route_path = route->route->get_turnout(from.get_turnout_id());
294 // Check that more than one path is available
295 unsigned ep_paths = track.endpoint().paths;
296 if(!(ep_paths&(ep_paths-1)))
299 // Choose some other path
300 for(int i=0; ep_paths>>i; ++i)
301 if((ep_paths&(1<<i)) && i!=route_path)
307 entry = track.entry();
311 track = track.next(route->route->get_path(*track));
313 if(!track || track.looped())
317 TrackIter track = TrackIter(&from, entry).next(path);
322 for(list<RouteRef>::iterator i=routes.begin(); i!=routes.end(); ++i)
323 tracks.insert(i->route->get_tracks().begin(), i->route->get_tracks().end());
324 RefPtr<Route> diversion = Route::find(track, tracks);
328 diversion->set_name("Diversion");
329 diversion->add_track(from);
330 diversion->set_turnout(from.get_turnout_id(), path);
332 if(!is_valid_diversion(*diversion, TrackIter(&from, entry)))
335 // Follow the diversion route until we get back to the original route
336 list<RouteRef>::iterator end = routes.end();
339 for(list<RouteRef>::iterator i=route; (end==routes.end() && i!=routes.end()); ++i)
340 if(i->route->has_track(*track))
343 if(end!=routes.end())
345 else if(!diversion->has_track(*track))
346 throw LogicError("Pathfinder returned a bad route");
348 track = track.next(diversion->get_path(*track));
352 // We are rejoining the same route we diverted from, duplicate it
353 routes.insert(end, *route);
357 routes.erase(route, end);
359 routes.insert(end, RouteRef(diversion.release(), from.get_turnout_id()));
364 const Route *Train::get_route() const
368 return routes.front().route;
371 void Train::place(Block &block, unsigned entry)
373 if(controller->get_speed())
374 throw InvalidState("Must be stopped before placing");
379 accurate_position = false;
381 if(!block.reserve(this))
383 set_status("Unplaced");
387 blocks.push_back(BlockIter(&block, entry));
390 TrackIter track = BlockIter(&block, entry).reverse().track_iter();
391 vehicles.front()->place(*track, track.entry(), 0, Vehicle::FRONT_BUFFER);
395 const Block::Endpoint &bep = block.get_endpoint(entry);
396 vehicles.back()->place(*bep.track, bep.track_ep, 0, Vehicle::BACK_BUFFER);
400 void Train::unplace()
402 if(controller->get_speed())
403 throw InvalidState("Must be stopped before unplacing");
408 accurate_position = false;
410 for(vector<Vehicle *>::iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
413 set_status("Unplaced");
416 bool Train::free_block(Block &block)
418 float margin = 10*layout.get_catalogue().get_scale();
419 if(get_reserved_distance_until(&block, false)<controller->get_braking_distance()*1.3+margin)
423 for(BlockList::iterator i=cur_blocks_end; i!=blocks.end(); ++i)
425 if(i->block()==&block)
429 release_blocks(i, blocks.end());
432 else if((*i)->get_sensor_id())
439 void Train::free_noncritical_blocks()
444 if(controller->get_speed()==0)
446 release_blocks(cur_blocks_end, blocks.end());
450 float margin = 10*layout.get_catalogue().get_scale();
451 float min_dist = controller->get_braking_distance()*1.3+margin;
453 Vehicle &veh = *(reverse ? vehicles.back() : vehicles.front());
455 TrackIter track(veh.get_track(), veh.get_entry());
456 BlockList::iterator block = blocks.begin();
458 while(block!=blocks.end() && !(*block)->has_track(*track))
461 if(block==cur_blocks_end)
465 float dist = veh.get_offset();
469 dist = track->get_type().get_path_length(track->get_active_path())-dist;
470 dist -= veh.get_type().get_length()/2;
475 track = track.next();
477 if(!(*block)->has_track(*track))
480 if(block==cur_blocks_end)
482 if(block==blocks.end())
485 if(dist>min_dist && nsens>0)
487 release_blocks(block, blocks.end());
491 if(in_rsv && (*block)->get_sensor_id())
495 dist += track->get_type().get_path_length(track->get_active_path());
499 int Train::get_entry_to_block(Block &block) const
501 for(BlockList::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
502 if(i->block()==&block)
507 float Train::get_reserved_distance() const
509 return get_reserved_distance_until(0, false);
512 void Train::tick(const Time::TimeStamp &t, const Time::TimeDelta &dt)
514 if(!active && stop_timeout && t>=stop_timeout)
516 release_blocks(cur_blocks_end, blocks.end());
517 stop_timeout = Time::TimeStamp();
520 Driver &driver = layout.get_driver();
524 controller->tick(dt);
525 float speed = controller->get_speed();
526 unsigned speed_step = find_speed_step(speed);
528 if(controller->get_reverse()!=reverse)
530 reverse = controller->get_reverse();
531 driver.set_loco_reverse(address, reverse);
533 release_blocks(cur_blocks_end, blocks.end());
534 reverse_blocks(blocks);
538 if(speed_step!=current_speed_step && !speed_changing && !driver.is_halted() && driver.get_power())
540 speed_changing = true;
541 driver.set_loco_speed(address, speed_step);
546 set_status(format("Traveling %d kmh", get_travel_speed()));
548 set_status("Waiting");
556 Vehicle &vehicle = *(reverse ? vehicles.back() : vehicles.front());
557 Track *track = vehicle.get_track();
560 for(BlockList::const_iterator i=blocks.begin(); (!ok && i!=cur_blocks_end); ++i)
561 ok = (*i)->has_track(*track);
564 if(real_speed.size()>1)
565 d = get_real_speed(current_speed_step)*(dt/Time::sec);
567 d = speed*(dt/Time::sec);
570 SetFlag setf(advancing);
571 vehicle.advance(reverse ? -d : d);
573 else if(accurate_position)
576 if(overshoot_dist>40*layout.get_catalogue().get_scale())
578 layout.emergency(name+" has not arrived at sensor");
579 accurate_position = false;
583 else if(end_of_route && cur_blocks_end==blocks.end())
586 signal_arrived.emit();
590 if(!blocks.empty() && !blocks.front()->get_sensor_id())
592 float dist = get_reserved_distance_until(&*blocks.front(), true);
594 if(dist>10*layout.get_catalogue().get_scale())
596 blocks.front()->reserve(0);
602 void Train::save(list<DataFile::Statement> &st) const
604 st.push_back((DataFile::Statement("name"), name));
606 st.push_back((DataFile::Statement("priority"), priority));
608 for(vector<Vehicle *>::const_iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
609 if(i!=vehicles.begin())
610 st.push_back((DataFile::Statement("vehicle"), (*i)->get_type().get_article_number()));
612 for(unsigned i=0; i<real_speed.size(); ++i)
613 if(real_speed[i].weight)
614 st.push_back((DataFile::Statement("real_speed"), i, real_speed[i].speed, real_speed[i].weight));
616 if(!blocks.empty() && cur_blocks_end!=blocks.begin())
618 BlockList blks(blocks.begin(), BlockList::const_iterator(cur_blocks_end));
620 reverse_blocks(blks);
622 BlockIter prev = blks.front().flip();
623 st.push_back((DataFile::Statement("block_hint"), prev->get_id()));
625 for(BlockList::const_iterator i=blks.begin(); i!=blks.end(); ++i)
626 st.push_back((DataFile::Statement("block"), (*i)->get_id()));
631 list<RouteRef>::const_iterator i = routes.begin();
632 for(; (i!=routes.end() && i->route->is_temporary()); ++i) ;
634 st.push_back((DataFile::Statement("route"), i->route->get_name()));
639 DataFile::Statement ss("timetable");
640 timetable->save(ss.sub);
645 void Train::control_changed(const Controller::Control &ctrl)
647 signal_control_changed.emit(ctrl.name, ctrl.value);
650 void Train::loco_speed_event(unsigned addr, unsigned speed, bool)
654 current_speed_step = speed;
655 speed_changing = false;
660 void Train::loco_func_event(unsigned addr, unsigned func, bool state)
662 if(addr==address || (addr==address+1 && loco_type.get_max_function()>4))
667 functions |= 1<<func;
669 functions &= ~(1<<func);
671 signal_function_changed.emit(func, state);
675 void Train::sensor_event(unsigned addr, bool state)
679 // Find the first sensor block from our reserved blocks that isn't this sensor
680 BlockList::iterator end;
682 for(end=cur_blocks_end; end!=blocks.end(); ++end)
683 if((*end)->get_sensor_id())
685 if((*end)->get_sensor_id()!=addr)
700 // Compute speed and update related state
701 float travel_time_secs = (Time::now()-last_entry_time)/Time::sec;
705 if(current_speed_step>0)
707 RealSpeed &rs = real_speed[current_speed_step];
708 rs.add(travel_dist/travel_time_secs, travel_time_secs);
710 set_status(format("Traveling %d kmh", get_travel_speed()));
714 for(BlockList::iterator j=cur_blocks_end; j!=end; ++j)
716 travel_dist += (*j)->get_path_length(j->entry());
718 if((*j)->get_sensor_id()==addr && !advancing)
720 TrackIter track = j->track_iter();
723 track = track.flip();
724 vehicles.back()->place(*track, track.entry(), 0, Vehicle::BACK_AXLE);
727 vehicles.front()->place(*track, track.entry(), 0, Vehicle::FRONT_AXLE);
730 last_entry_time = Time::now();
732 accurate_position = true;
735 // Check if we've reached the next route
738 const Route &route = *(++routes.begin())->route;
739 for(BlockList::iterator j=cur_blocks_end; j!=end; ++j)
740 if(route.has_track(*j->track_iter()))
744 signal_route_changed.emit(routes.front().route);
749 // Move blocks up to the next sensor to our current blocks
750 cur_blocks_end = end;
752 // Try to get more blocks if we're moving
757 layout.emergency("Sensor for "+name+" triggered out of order");
761 const Vehicle &veh = *(reverse ? vehicles.front() : vehicles.back());
763 // Find the first sensor in our current blocks that's still active
764 BlockList::iterator end = blocks.begin();
765 for(BlockList::iterator i=blocks.begin(); i!=cur_blocks_end; ++i)
767 if((*i)->has_track(*veh.get_track()))
769 if((*i)->get_sensor_id())
771 if(layout.get_driver().get_sensor((*i)->get_sensor_id()))
781 if(end!=blocks.begin() && end!=cur_blocks_end)
782 // Free blocks up to the last inactive sensor
783 release_blocks(blocks.begin(), end);
787 void Train::turnout_path_changed(Track &track)
789 for(list<BlockIter>::iterator i=blocks.begin(); i!=blocks.end(); ++i)
790 if((*i)->get_turnout_id()==track.get_turnout_id() && !reserving)
791 check_turnout_paths(false);
794 void Train::halt_event(bool h)
797 accurate_position = false;
800 void Train::block_reserved(const Block &block, const Train *train)
802 if(&block==pending_block && !train && !reserving)
806 void Train::reserve_more()
808 if(!active || blocks.empty() || end_of_route)
811 BlockIter start = blocks.back();
815 // See how many sensor blocks and how much track we already have
818 for(BlockList::const_iterator i=cur_blocks_end; i!=blocks.end(); ++i)
820 if((*i)->get_sensor_id())
823 dist += (*i)->get_path_length(i->entry());
826 list<RouteRef>::iterator cur_route = routes.begin();
827 advance_route(cur_route, *start.track_iter());
829 float approach_margin = 50*layout.get_catalogue().get_scale();
830 float min_dist = controller->get_braking_distance()*1.3+approach_margin*2;
832 BlockIter block = start;
833 list<BlockIter>::iterator good_end = blocks.end();
834 Track *divert_track = 0;
835 bool try_divert = false;
836 Train *blocking_train = 0;
837 BlockList contested_blocks;
839 SetFlag setf(reserving);
843 BlockIter last = block;
844 block = block.next(cur_route!=routes.end() ? cur_route->route : 0);
845 if(!block || block->get_endpoints().size()<2)
848 good_end = blocks.end();
852 TrackIter track = block.track_iter();
854 if(cur_route!=routes.end())
856 if(!advance_route(cur_route, *track))
858 // Keep the blocks if we arrived at the end of the route
861 good_end = blocks.end();
868 if(block->get_turnout_id() && !last->get_turnout_id())
870 /* We can keep the blocks if we arrive at a turnout from a non-turnout
871 block. Having a turnout block as our last reserved block is not good
872 as it would limit our diversion possibilities for little benefit. */
873 good_end = blocks.end();
874 if(nsens>=3 && dist>=min_dist)
880 if(block->get_train()!=blocking_train)
882 if(blocking_train->free_block(*contested_blocks.back()))
884 // Roll back and start actually reserving the blocks
885 block = blocks.back();
886 cur_route = routes.begin();
887 advance_route(cur_route, *block.track_iter().track());
888 if(blocking_train->get_priority()==priority)
889 blocking_train->yield_to(*this);
895 yield_to(*blocking_train);
896 pending_block = contested_blocks.front().block();
897 try_divert = divert_track;
903 contested_blocks.push_back(block);
908 bool reserved = block->reserve(this);
911 /* We've found another train. If it wants to exit the block from the
912 same endpoint we're trying to enter from or the other way around,
913 treat it as coming towards us. Otherwise treat it as going in the
915 Train *other_train = block->get_train();
916 int other_entry = other_train->get_entry_to_block(*block);
918 throw LogicError("Block reservation inconsistency");
920 unsigned exit = block.reverse().entry();
921 unsigned other_exit = BlockIter(block.block(), other_entry).reverse().entry();
922 bool entry_conflict = (block.entry()==other_exit);
923 bool exit_conflict = (exit==static_cast<unsigned>(other_entry));
924 if(!entry_conflict && !last->get_turnout_id())
925 /* The other train is not coming to the blocks we're holding, so we
927 good_end = blocks.end();
929 int other_prio = other_train->get_priority();
931 if(!entry_conflict && !exit_conflict && other_prio<priority)
933 /* Ask a lesser priority train going to the same direction to free
935 if(other_train->free_block(*block))
936 reserved = block->reserve(this);
938 else if(other_train!=yielding_to && (other_prio<priority || (other_prio==priority && entry_conflict)))
940 /* A lesser priority train is coming at us, we must ask it to free
941 enough blocks to get clear of it to avoid a potential deadlock */
942 blocking_train = other_train;
943 contested_blocks.clear();
944 contested_blocks.push_back(block);
947 else if(divert_track && (entry_conflict || exit_conflict))
948 // We are blocked, but there's a diversion possibility
953 pending_block = &*block;
958 if(block->get_turnout_id())
960 const TrackType::Endpoint &track_ep = track.endpoint();
961 bool multiple_paths = (track_ep.paths&(track_ep.paths-1));
963 if(multiple_paths && cur_route!=routes.end() && cur_route->diversion!=block->get_turnout_id())
964 /* There's multiple paths to be taken and we are on a route - take
965 note of the diversion possibility */
966 divert_track = &*track;
969 if(!contested_blocks.empty() && contested_blocks.front()==block)
970 contested_blocks.pop_front();
972 blocks.push_back(block);
974 if(cur_blocks_end==blocks.end())
976 if(clear_blocks_end==blocks.end())
978 if(good_end==blocks.end())
981 if(block->get_sensor_id())
984 dist += block->get_path_length(block.entry());
987 // Unreserve blocks that were not good
988 release_blocks(good_end, blocks.end());
990 if(blocks.back()!=start)
991 // We got some new blocks, so no longer need to yield
994 check_turnout_paths(true);
996 // Make any sensorless blocks at the beginning immediately current
997 while(cur_blocks_end!=clear_blocks_end && !(*cur_blocks_end)->get_sensor_id())
1000 if(try_divert && divert(*divert_track))
1004 void Train::check_turnout_paths(bool set)
1006 if(clear_blocks_end==blocks.end())
1009 for(list<BlockIter>::iterator i=clear_blocks_end; i!=blocks.end(); ++i)
1011 if((*i)->get_turnout_id())
1013 TrackIter track = i->track_iter();
1014 const TrackType::Endpoint &track_ep = track.endpoint();
1017 list<BlockIter>::iterator j = i;
1018 if(++j!=blocks.end())
1020 TrackIter rev = j->track_iter().flip();
1021 unsigned mask = rev.endpoint().paths&track_ep.paths;
1022 for(path=0; mask>1; mask>>=1, ++path) ;
1027 if(path!=track->get_active_path())
1030 track->set_active_path(path);
1032 /* Check again, in case the driver was able to service the request
1034 if(!set || path!=track->get_active_path())
1039 if(i==clear_blocks_end)
1044 float Train::get_reserved_distance_until(const Block *until_block, bool back) const
1049 Vehicle &veh = *(reverse!=back ? vehicles.back() : vehicles.front());
1050 const VehicleType &vtype = veh.get_type();
1052 TrackIter track(veh.get_track(), veh.get_entry());
1053 if(!track) // XXX Probably unnecessary
1056 BlockList::const_iterator block = blocks.begin();
1057 while(block!=clear_blocks_end && !(*block)->has_track(*track))
1059 if(block==clear_blocks_end || &**block==until_block)
1062 float result = veh.get_offset();
1064 track = track.reverse();
1066 result = track->get_type().get_path_length(track->get_active_path())-result;
1067 result -= vtype.get_length()/2;
1071 track = track.next();
1075 if(!(*block)->has_track(*track))
1079 if(block==blocks.begin())
1086 if(block==clear_blocks_end)
1090 if(&**block==until_block)
1094 result += track->get_type().get_path_length(track->get_active_path());
1100 float Train::get_real_speed(unsigned i) const
1104 if(real_speed[i].weight)
1105 return real_speed[i].speed;
1109 for(low=i; low>0; --low)
1110 if(real_speed[low].weight)
1112 for(high=i; high<real_speed.size(); ++high)
1113 if(real_speed[high].weight)
1116 if(real_speed[high].weight)
1118 if(real_speed[low].weight)
1120 float f = float(i-low)/(high-low);
1121 return real_speed[low].speed*(1-f)+real_speed[high].speed*f;
1124 return real_speed[high].speed*float(i)/high;
1126 else if(real_speed[low].weight)
1127 return real_speed[low].speed*float(i)/low;
1132 unsigned Train::find_speed_step(float real) const
1134 if(real_speed.size()<=1)
1136 if(real<=real_speed[1].speed*0.5)
1142 for(unsigned i=0; (!high && i<real_speed.size()); ++i)
1143 if(real_speed[i].weight)
1146 if(real_speed[i].speed<real)
1153 unsigned limit = real_speed.size()/5;
1161 return min(min(static_cast<unsigned>(low*real/real_speed[low].speed), real_speed.size()-1), last+limit);
1164 float f = (real-real_speed[low].speed)/(real_speed[high].speed-real_speed[low].speed);
1165 return static_cast<unsigned>(low*(1-f)+high*f+0.5);
1168 float Train::get_travel_speed() const
1170 float speed = get_real_speed(current_speed_step);
1171 float scale = layout.get_catalogue().get_scale();
1172 return static_cast<int>(round(speed/scale*3.6/5))*5;
1175 void Train::set_status(const string &s)
1178 signal_status_changed.emit(s);
1181 void Train::release_blocks()
1183 release_blocks(blocks.begin(), blocks.end());
1186 void Train::release_blocks(BlockList::iterator begin, BlockList::iterator end)
1190 if(begin==cur_blocks_end)
1191 cur_blocks_end = end;
1192 if(begin==clear_blocks_end)
1193 clear_blocks_end = end;
1195 Block &block = **begin;
1196 blocks.erase(begin++);
1199 if(begin==blocks.end())
1200 end_of_route = false;
1204 void Train::reverse_blocks(BlockList &blks) const
1207 for(BlockList::iterator i=blks.begin(); i!=blks.end(); ++i)
1211 bool Train::advance_route(list<RouteRef>::iterator &iter, Track &track)
1213 while(iter!=routes.end() && !iter->route->has_track(track))
1215 if(iter==routes.end())
1218 list<RouteRef>::iterator next = iter;
1220 if(next!=routes.end() && next->diversion && next->route->has_track(track))
1226 Route *Train::create_lead_route(Route *lead, const Route *target)
1230 lead = new Route(layout);
1231 lead->set_name("Lead");
1232 lead->set_temporary(true);
1235 set<Track *> tracks;
1236 for(BlockList::iterator i=blocks.begin(); i!=blocks.end(); ++i)
1238 const set<Track *> &btracks = (*i)->get_tracks();
1239 for(set<Track *>::const_iterator j=btracks.begin(); j!=btracks.end(); ++j)
1240 if(!target || !target->has_track(**j))
1244 lead->add_tracks(tracks);
1249 bool Train::is_valid_diversion(const Route &diversion, const TrackIter &from)
1251 float diversion_len = 0;
1252 TrackLoopIter track1 = from;
1253 while(diversion.has_track(*track1))
1255 unsigned path = diversion.get_path(*track1);
1256 diversion_len += track1->get_type().get_path_length(path);
1258 track1 = track1.next(path);
1264 list<RouteRef>::iterator route = routes.begin();
1265 if(!advance_route(route, *from))
1268 float route_len = 0;
1269 TrackLoopIter track2 = from;
1272 unsigned path = route->route->get_path(*track2);
1273 route_len += track2->get_type().get_path_length(path);
1275 bool ok = (track2!=from && diversion.has_track(*track2));
1277 track2 = track2.next(path);
1285 if(!advance_route(route, *track2))
1289 // Must end up at the same place through both routes
1293 return diversion_len<route_len*1.2;
1297 Train::RouteRef::RouteRef(const Route *r, unsigned d):
1303 Train::RealSpeed::RealSpeed():
1308 void Train::RealSpeed::add(float s, float w)
1310 speed = (speed*weight+s*w)/(weight+w);
1311 weight = min(weight+w, 300.0f);
1315 Train::Loader::Loader(Train &t):
1316 DataFile::BasicLoader<Train>(t),
1320 add("block", &Loader::block);
1321 add("block_hint", &Loader::block_hint);
1322 add("name", &Loader::name);
1323 add("priority", &Train::priority);
1324 add("real_speed", &Loader::real_speed);
1325 add("route", &Loader::route);
1326 add("timetable", &Loader::timetable);
1327 add("vehicle", &Loader::vehicle);
1330 void Train::Loader::finish()
1332 if(!obj.blocks.empty())
1334 TrackIter track = obj.blocks.front().track_iter();
1335 float offset = 2*obj.layout.get_catalogue().get_scale();
1336 obj.vehicles.back()->place(*track, track.entry(), offset, Vehicle::BACK_BUFFER);
1338 obj.set_status("Stopped");
1342 void Train::Loader::block(unsigned id)
1350 blk = &obj.layout.get_block(id);
1352 catch(const KeyError &)
1354 blocks_valid = false;
1360 entry = blk->get_endpoint_by_link(*prev_block);
1365 obj.blocks.push_back(BlockIter(blk, entry));
1367 if(blk->get_sensor_id())
1368 obj.layout.get_driver().set_sensor(blk->get_sensor_id(), true);
1373 void Train::Loader::block_hint(unsigned id)
1377 prev_block = &obj.layout.get_block(id);
1379 catch(const KeyError &)
1381 blocks_valid = false;
1385 void Train::Loader::name(const string &n)
1390 void Train::Loader::real_speed(unsigned i, float speed, float weight)
1392 if(i>=obj.real_speed.size())
1394 obj.real_speed[i].speed = speed;
1395 obj.real_speed[i].weight = weight;
1398 void Train::Loader::route(const string &n)
1400 obj.set_route(&obj.layout.get_route(n));
1403 void Train::Loader::timetable()
1406 throw InvalidState("A timetable has already been loaded");
1408 obj.timetable = new Timetable(obj);
1409 load_sub(*obj.timetable);
1412 void Train::Loader::vehicle(ArticleNumber art_nr)
1414 const VehicleType &vtype = obj.layout.get_catalogue().get_vehicle(art_nr);
1415 Vehicle *veh = new Vehicle(obj.layout, vtype);
1416 obj.vehicles.back()->attach_back(*veh);
1417 obj.vehicles.push_back(veh);
1420 } // namespace Marklin