]> git.tdb.fi Git - r2c2.git/blob - source/libmarklin/train.cpp
Prevent some undesirable recursive calls
[r2c2.git] / source / libmarklin / train.cpp
1 /* $Id$
2
3 This file is part of the MSP Märklin suite
4 Copyright © 2006-2010  Mikkosoft Productions, Mikko Rasa
5 Distributed under the GPL
6 */
7
8 #include <cmath>
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"
14 #include "driver.h"
15 #include "layout.h"
16 #include "route.h"
17 #include "simplecontroller.h"
18 #include "timetable.h"
19 #include "tracktype.h"
20 #include "train.h"
21 #include "vehicle.h"
22 #include "vehicletype.h"
23
24 using namespace std;
25 using namespace Msp;
26
27 namespace Marklin {
28
29 Train::Train(Layout &l, const VehicleType &t, unsigned a):
30         layout(l),
31         loco_type(t),
32         address(a),
33         priority(0),
34         pending_block(0),
35         reserving(false),
36         advancing(false),
37         controller(new AIControl(*this, new SimpleController)),
38         timetable(0),
39         active(false),
40         current_speed(0),
41         speed_changing(false),
42         reverse(false),
43         functions(0),
44         route(0),
45         next_route(0),
46         end_of_route(false),
47         status("Unplaced"),
48         travel_dist(0),
49         pure_speed(false),
50         real_speed(15),
51         accurate_position(false),
52         overshoot_dist(false)
53 {
54         if(!loco_type.is_locomotive())
55                 throw InvalidParameterValue("Initial vehicle must be a locomotive");
56
57         vehicles.push_back(new Vehicle(layout, loco_type));
58
59         layout.add_train(*this);
60
61         layout.get_driver().add_loco(address);
62         layout.get_driver().signal_loco_speed.connect(sigc::mem_fun(this, &Train::loco_speed_event));
63         layout.get_driver().signal_loco_function.connect(sigc::mem_fun(this, &Train::loco_func_event));
64
65         layout.signal_block_reserved.connect(sigc::mem_fun(this, &Train::block_reserved));
66         layout.get_driver().signal_sensor.connect(sigc::mem_fun(this, &Train::sensor_event));
67         layout.get_driver().signal_turnout.connect(sigc::mem_fun(this, &Train::turnout_event));
68
69         layout.get_driver().signal_halt.connect(sigc::mem_fun(this, &Train::halt_event));
70
71         controller->signal_control_changed.connect(sigc::mem_fun(this, &Train::control_changed));
72 }
73
74 Train::~Train()
75 {
76         delete controller;
77         delete timetable;
78         for(vector<Vehicle *>::iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
79                 delete *i;
80         layout.remove_train(*this);
81 }
82
83 void Train::set_name(const string &n)
84 {
85         name = n;
86
87         signal_name_changed.emit(name);
88 }
89
90 void Train::set_priority(int p)
91 {
92         priority = p;
93 }
94
95 void Train::add_vehicle(const VehicleType &vt)
96 {
97         Vehicle *veh = new Vehicle(layout, vt);
98         vehicles.back()->attach_back(*veh);
99         vehicles.push_back(veh);
100 }
101
102 void Train::remove_vehicle(unsigned i)
103 {
104         if(i>=vehicles.size())
105                 throw InvalidParameterValue("Vehicle index out of range");
106         if(i==0)
107                 throw InvalidParameterValue("Can't remove the locomotive");
108         delete vehicles[i];
109         vehicles.erase(vehicles.begin()+i);
110         if(i<vehicles.size())
111                 vehicles[i-1]->attach_back(*vehicles[i]);
112 }
113
114 unsigned Train::get_n_vehicles() const
115 {
116         return vehicles.size();
117 }
118
119 Vehicle &Train::get_vehicle(unsigned i)
120 {
121         if(i>=vehicles.size())
122                 throw InvalidParameterValue("Vehicle index out of range");
123         return *vehicles[i];
124 }
125
126 const Vehicle &Train::get_vehicle(unsigned i) const
127 {
128         if(i>=vehicles.size())
129                 throw InvalidParameterValue("Vehicle index out of range");
130         return *vehicles[i];
131 }
132
133 void Train::set_control(const string &n, float v)
134 {
135         controller->set_control(n, v);
136 }
137
138 void Train::set_active(bool a)
139 {
140         if(a==active)
141                 return;
142         if(!a && controller->get_speed())
143                 throw InvalidState("Can't deactivate while moving");
144
145         active = a;
146         if(active)
147         {
148                 stop_timeout = Time::TimeStamp();
149                 reserve_more();
150         }
151         else
152         {
153                 stop_timeout = Time::now()+2*Time::sec;
154                 set_status("Stopped");
155         }
156 }
157
158 void Train::set_function(unsigned func, bool state)
159 {
160         if(!loco_type.get_functions().count(func))
161                 throw InvalidParameterValue("Invalid function");
162         if(func<5)
163                 layout.get_driver().set_loco_function(address, func, state);
164         else
165                 layout.get_driver().set_loco_function(address+1, func-4, state);
166 }
167
168 float Train::get_control(const string &ctrl) const
169 {
170         return controller->get_control(ctrl).value;
171 }
172
173 float Train::get_speed() const
174 {
175         return controller->get_speed();
176 }
177
178 bool Train::get_function(unsigned func) const
179 {
180         return (functions>>func)&1;
181 }
182
183 void Train::set_timetable(Timetable *tt)
184 {
185         delete timetable;
186         timetable = tt;
187 }
188
189 void Train::set_route(const Route *r)
190 {
191         if(!rsv_blocks.empty())
192         {
193                 for(list<BlockRef>::iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
194                         if(i->block->get_sensor_id())
195                         {
196                                 release_blocks(rsv_blocks, ++i, rsv_blocks.end());
197                                 break;
198                         }
199         }
200
201         route = r;
202         next_route = 0;
203         end_of_route = false;
204
205         if(route)
206         {
207                 BlockRef &last = (rsv_blocks.empty() ? cur_blocks.back() : rsv_blocks.back());
208                 BlockRef next = last.next();
209                 const Block::Endpoint &ep = next.block->get_endpoints()[next.entry];
210                 if(!route->get_tracks().count(ep.track))
211                 {
212                         next_route = route;
213                         route = Route::find(*ep.track, ep.track_ep, *next_route);
214                 }
215         }
216
217         reserve_more();
218
219         signal_route_changed.emit(route);
220 }
221
222 void Train::go_to(const Track &to)
223 {
224         for(list<BlockRef>::const_iterator i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
225                 if(i->block->get_tracks().count(const_cast<Track *>(&to)))
226                 {
227                         signal_arrived.emit();
228                         set_route(0);
229                         return;
230                 }
231
232         BlockRef *last = 0;
233         if(rsv_blocks.empty())
234                 last = &cur_blocks.back();
235         else
236         {
237                 for(list<BlockRef>::iterator i=rsv_blocks.begin(); (i!=rsv_blocks.end() && !last); ++i)
238                         if(i->block->get_sensor_id())
239                                 last = &*i;
240         }
241
242         BlockRef next = last->next();
243         const Block::Endpoint &ep = next.block->get_endpoints()[next.entry];
244
245         set_route(Route::find(*ep.track, ep.track_ep, to));
246 }
247
248 void Train::place(Block &block, unsigned entry)
249 {
250         if(controller->get_speed())
251                 throw InvalidState("Must be stopped before placing");
252
253         release_blocks(rsv_blocks);
254         release_blocks(cur_blocks);
255
256         set_active(false);
257         accurate_position = false;
258
259         if(!block.reserve(this))
260         {
261                 set_status("Unplaced");
262                 return;
263         }
264
265         cur_blocks.push_back(BlockRef(&block, entry));
266         if(reverse)
267         {
268                 unsigned exit = block.traverse(entry);
269                 const Block::Endpoint &bep = block.get_endpoints()[exit];
270                 Track *track = bep.track->get_link(bep.track_ep);
271                 unsigned ep = track->get_endpoint_by_link(*bep.track);
272                 vehicles.front()->place(track, ep, 0, Vehicle::FRONT_BUFFER);
273         }
274         else
275         {
276                 const Block::Endpoint &bep = block.get_endpoints()[entry];
277                 vehicles.back()->place(bep.track, bep.track_ep, 0, Vehicle::BACK_BUFFER);
278         }
279 }
280
281 bool Train::free_block(Block &block)
282 {
283         unsigned nsens = 0;
284         for(list<BlockRef>::iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
285         {
286                 if(i->block==&block)
287                 {
288                         if(nsens<1)
289                                 return false;
290                         release_blocks(rsv_blocks, i, rsv_blocks.end());
291                         return true;
292                 }
293                 else if(i->block->get_sensor_id())
294                         ++nsens;
295         }
296
297         return false;
298 }
299
300 int Train::get_entry_to_block(Block &block) const
301 {
302         for(list<BlockRef>::const_iterator i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
303                 if(i->block==&block)
304                         return i->entry;
305         for(list<BlockRef>::const_iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
306                 if(i->block==&block)
307                         return i->entry;
308         return -1;
309 }
310
311 float Train::get_reserved_distance() const
312 {
313         Vehicle &veh = *(reverse ? vehicles.back() : vehicles.front());
314         const VehicleType &vtype = veh.get_type();
315
316         Track *track = veh.get_track();
317         if(!track)
318                 return 0;
319         unsigned entry = veh.get_entry();
320
321         float result = -vtype.get_length()/2;
322         if(reverse)
323         {
324                 entry = track->traverse(entry);
325                 result += veh.get_offset();
326         }
327         else
328                 result -= veh.get_offset();
329
330         bool first = true;
331         list<BlockRef>::const_iterator block = cur_blocks.begin();
332         while(1)
333         {
334                 if(!first || !reverse)
335                         result += track->get_type().get_path_length(track->get_active_path());
336                 first = false;
337
338                 if(track->get_type().get_endpoints().size()<2)
339                         return result;
340
341                 unsigned exit = track->traverse(entry);
342                 Track *next = track->get_link(exit);
343
344                 while(!block->block->get_tracks().count(next))
345                 {
346                         ++block;
347                         if(block==cur_blocks.end())
348                                 block = rsv_blocks.begin();
349                         if(block==rsv_blocks.end())
350                                 return result;
351                 }
352
353                 entry = next->get_endpoint_by_link(*track);
354                 track = next;
355         }
356 }
357
358 void Train::tick(const Time::TimeStamp &t, const Time::TimeDelta &dt)
359 {
360         if(!active && stop_timeout && t>=stop_timeout)
361         {
362                 release_blocks(rsv_blocks);
363                 end_of_route = false;
364                 stop_timeout = Time::TimeStamp();
365         }
366
367         Driver &driver = layout.get_driver();
368
369         if(timetable)
370                 timetable->tick(t);
371         controller->tick(dt);
372         float speed = controller->get_speed();
373         unsigned speed_notch = find_speed(speed);
374
375         if(controller->get_reverse()!=reverse)
376         {
377                 reverse = controller->get_reverse();
378                 driver.set_loco_reverse(address, reverse);
379
380                 release_blocks(rsv_blocks);
381                 reverse_blocks(cur_blocks);
382
383                 reserve_more();
384         }
385         if(speed_notch!=current_speed && !speed_changing && !driver.is_halted() && driver.get_power())
386         {
387                 speed_changing = true;
388                 driver.set_loco_speed(address, speed_notch);
389
390                 pure_speed = false;
391
392                 if(speed_notch)
393                         set_status(format("Traveling %d kmh", get_travel_speed()));
394                 else
395                         set_status("Waiting");
396         }
397
398         if(speed)
399         {
400                 if(!active)
401                         set_active(true);
402
403                 Vehicle &vehicle = *(reverse ? vehicles.back() : vehicles.front());
404                 Track *track = vehicle.get_track();
405
406                 bool ok = false;
407                 for(list<BlockRef>::const_iterator i=cur_blocks.begin(); (!ok && i!=cur_blocks.end()); ++i)
408                         ok = i->block->get_tracks().count(track);
409
410                 float d = get_real_speed(current_speed)*(dt/Time::sec);
411                 if(ok)
412                 {
413                         advancing = true;
414                         vehicle.advance(reverse ? -d : d);
415                         advancing = false;
416                 }
417                 else if(accurate_position)
418                 {
419                         overshoot_dist += d;
420                         if(overshoot_dist>40*layout.get_catalogue().get_scale())
421                         {
422                                 layout.emergency(name+" has not arrived at sensor");
423                                 accurate_position = false;
424                         }
425                 }
426         }
427         else if(end_of_route && rsv_blocks.empty())
428         {
429                 signal_arrived.emit();
430                 set_route(0);
431         }
432
433         if(!cur_blocks.empty() && !cur_blocks.front().block->get_sensor_id())
434         {
435                 Vehicle &veh = *(reverse ? vehicles.front() : vehicles.back());
436
437                 list<BlockRef>::iterator i = cur_blocks.begin();
438                 const Block::Endpoint &bep = i->block->get_endpoints()[i->entry];
439
440                 Track *track = bep.track;
441                 unsigned entry = bep.track_ep;
442
443                 bool found = false;
444                 float dist = veh.get_offset();
445                 if(reverse)
446                         dist = veh.get_track()->get_type().get_path_length(veh.get_track()->get_active_path())-dist;
447                 dist -= veh.get_type().get_length()/2;
448                 while(1)
449                 {
450                         if(track==veh.get_track())
451                         {
452                                 found = true;
453                                 break;
454                         }
455
456                         if(i!=cur_blocks.begin())
457                         {
458                                 float path_len = track->get_type().get_path_length(track->get_active_path());
459                                 dist += path_len;
460                         }
461
462                         unsigned exit = track->traverse(entry);
463                         Track *next = track->get_link(exit);
464                         entry = next->get_endpoint_by_link(*track);
465                         track = next;
466
467                         if(!i->block->get_tracks().count(track))
468                         {
469                                 ++i;
470                                 if(i==cur_blocks.end())
471                                         break;
472                         }
473                 }
474
475                 if(found && i!=cur_blocks.begin() && dist>10*layout.get_catalogue().get_scale())
476                 {
477                         cur_blocks.front().block->reserve(0);
478                         cur_blocks.erase(cur_blocks.begin());
479                 }
480         }
481 }
482
483 void Train::save(list<DataFile::Statement> &st) const
484 {
485         st.push_back((DataFile::Statement("name"), name));
486
487         st.push_back((DataFile::Statement("priority"), priority));
488
489         for(vector<Vehicle *>::const_iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
490                 if(i!=vehicles.begin())
491                         st.push_back((DataFile::Statement("vehicle"), (*i)->get_type().get_article_number()));
492
493         for(unsigned i=0; i<=14; ++i)
494                 if(real_speed[i].weight)
495                         st.push_back((DataFile::Statement("real_speed"), i, real_speed[i].speed, real_speed[i].weight));
496
497         if(!cur_blocks.empty())
498         {
499                 list<BlockRef> blocks = cur_blocks;
500                 if(reverse)
501                         reverse_blocks(blocks);
502
503                 Block *prev = blocks.front().block->get_endpoints()[blocks.front().entry].link;
504                 st.push_back((DataFile::Statement("block_hint"), prev->get_id()));
505
506                 for(list<BlockRef>::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
507                         st.push_back((DataFile::Statement("block"), i->block->get_id()));
508         }
509
510         if(route)
511         {
512                 if(!route->is_temporary())
513                         st.push_back((DataFile::Statement("route"), route->get_name()));
514                 else if(next_route && !next_route->is_temporary())
515                         st.push_back((DataFile::Statement("route"), next_route->get_name()));
516         }
517
518         if(timetable)
519         {
520                 DataFile::Statement ss("timetable");
521                 timetable->save(ss.sub);
522                 st.push_back(ss);
523         }
524 }
525
526 void Train::control_changed(const Controller::Control &ctrl)
527 {
528         signal_control_changed.emit(ctrl.name, ctrl.value);
529 }
530
531 void Train::loco_speed_event(unsigned addr, unsigned speed, bool)
532 {
533         if(addr==address)
534         {
535                 current_speed = speed;
536                 speed_changing = false;
537                 pure_speed = false;
538         }
539 }
540
541 void Train::loco_func_event(unsigned addr, unsigned func, bool state)
542 {
543         if(addr==address || (addr==address+1 && loco_type.get_max_function()>4))
544         {
545                 if(addr==address+1)
546                         func += 4;
547                 if(state)
548                         functions |= 1<<func;
549                 else
550                         functions &= ~(1<<func);
551
552                 signal_function_changed.emit(func, state);
553         }
554 }
555
556 void Train::sensor_event(unsigned addr, bool state)
557 {
558         if(state)
559         {
560                 // Find the first sensor block from our reserved blocks that isn't this sensor
561                 list<BlockRef>::iterator i;
562                 unsigned result = 0;
563                 for(i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
564                         if(i->block->get_sensor_id())
565                         {
566                                 if(i->block->get_sensor_id()!=addr)
567                                 {
568                                         if(result==0)
569                                                 result = 2;
570                                         else if(result==1)
571                                                 break;
572                                 }
573                                 else if(result==0)
574                                         result = 1;
575                                 else if(result==2)
576                                         result = 3;
577                         }
578
579                 if(result==1 && i!=rsv_blocks.begin())
580                 {
581                         // Compute speed and update related state
582                         float travel_time_secs = (Time::now()-last_entry_time)/Time::sec;
583
584                         if(pure_speed)
585                         {
586                                 if(current_speed)
587                                 {
588                                         RealSpeed &rs = real_speed[current_speed];
589                                         rs.add(travel_dist/travel_time_secs, travel_time_secs);
590                                 }
591                                 set_status(format("Traveling %d kmh", get_travel_speed()));
592                         }
593
594                         travel_dist = 0;
595                         float block_len;
596                         for(list<BlockRef>::iterator j=rsv_blocks.begin(); j!=i; ++j)
597                         {
598                                 j->block->traverse(j->entry, &block_len);
599                                 travel_dist += block_len;
600
601                                 if(j->block->get_sensor_id()==addr && !advancing)
602                                 {
603                                         const Block::Endpoint &bep = j->block->get_endpoints()[j->entry];
604                                         if(reverse)
605                                         {
606                                                 Track *track = bep.track->get_link(bep.track_ep);
607                                                 unsigned ep = track->get_endpoint_by_link(*bep.track);
608                                                 vehicles.back()->place(track, ep, 0, Vehicle::BACK_AXLE);
609                                         }
610                                         else
611                                                 vehicles.front()->place(bep.track, bep.track_ep, 0, Vehicle::FRONT_AXLE);
612                                 }
613                         }
614                         last_entry_time = Time::now();
615                         pure_speed = true;
616                         accurate_position = true;
617                         overshoot_dist = 0;
618
619                         // Check if we've reached the next route
620                         if(next_route)
621                         {
622                                 const set<const Track *> &rtracks = next_route->get_tracks();
623                                 for(list<BlockRef>::iterator j=rsv_blocks.begin(); j!=i; ++j)
624                                         if(rtracks.count(j->block->get_endpoints()[j->entry].track))
625                                         {
626                                                 route = next_route;
627                                                 next_route = 0;
628                                                 // XXX Exceptions?
629                                                 signal_route_changed.emit(route);
630                                                 break;
631                                         }
632                         }
633
634                         // Move blocks up to the next sensor to our current blocks
635                         cur_blocks.splice(cur_blocks.end(), rsv_blocks, rsv_blocks.begin(), i);
636
637                         // Try to get more blocks if we're moving
638                         if(active)
639                                 reserve_more();
640                 }
641                 else if(result==3)
642                         layout.emergency("Sensor for "+name+" triggered out of order");
643         }
644         else
645         {
646                 // Find the first sensor in our current blocks that's still active
647                 list<BlockRef>::iterator end = cur_blocks.begin();
648                 for(list<BlockRef>::iterator i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
649                         if(i->block->get_sensor_id())
650                         {
651                                 if(layout.get_driver().get_sensor(i->block->get_sensor_id()))
652                                         break;
653                                 else
654                                 {
655                                         end = i;
656                                         ++end;
657                                 }
658                         }
659                 
660                 if(end!=cur_blocks.begin())
661                         // Free blocks up to the last inactive sensor
662                         release_blocks(cur_blocks, cur_blocks.begin(), end);
663         }
664 }
665
666 void Train::turnout_event(unsigned addr, bool)
667 {
668         if(pending_block)
669         {
670                 unsigned pending_addr = pending_block->get_turnout_id();
671                 bool double_addr = (*pending_block->get_tracks().begin())->get_type().is_double_address();
672                 if(addr==pending_addr || (double_addr && addr==pending_addr+1))
673                 {
674                         if(reserving)
675                                 pending_block = 0;
676                         else
677                                 reserve_more();
678                 }
679         }
680 }
681
682 void Train::halt_event(bool h)
683 {
684         if(h)
685                 accurate_position = false;
686 }
687
688 void Train::block_reserved(const Block &block, const Train *train)
689 {
690         if(&block==pending_block && !train)
691                 reserve_more();
692 }
693
694 unsigned Train::reserve_more()
695 {
696         if(!active)
697                 return 0;
698
699         BlockRef *last = 0;
700         if(!rsv_blocks.empty())
701                 last = &rsv_blocks.back();
702         else if(!cur_blocks.empty())
703                 last = &cur_blocks.back();
704         if(!last)
705                 return 0;
706
707         pending_block = 0;
708
709         // See how many sensor blocks we already have
710         unsigned nsens = 0;
711         for(list<BlockRef>::const_iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
712                 if(i->block->get_sensor_id())
713                         ++nsens;
714         
715         if(end_of_route)
716                 return nsens;
717
718         const Route *cur_route = 0;
719         if(route)
720         {
721                 const set<Track *> &tracks = last->block->get_tracks();
722                 for(set<Track *>::const_iterator i=tracks.begin(); (cur_route!=route && i!=tracks.end()); ++i)
723                 {
724                         if(route->get_tracks().count(*i))
725                                 cur_route = route;
726                         else if(next_route && next_route->get_tracks().count(*i))
727                                 cur_route = next_route;
728                 }
729         }
730
731         reserving = true;
732
733         bool got_more = false;
734         BlockRef *good = last;
735         unsigned good_sens = nsens;
736         while(good_sens<3)
737         {
738                 // Traverse to the next block
739                 unsigned exit = last->block->traverse(last->entry);
740                 Block *link = last->block->get_link(exit);
741                 if(!link)
742                         break;
743
744                 int entry = link->get_endpoint_by_link(*last->block);
745                 if(entry<0)
746                         throw LogicError("Block links are inconsistent!");
747
748                 const Block::Endpoint &entry_ep = link->get_endpoints()[entry];
749
750                 if(cur_route)
751                 {
752                         if(cur_route!=next_route && next_route && next_route->get_tracks().count(entry_ep.track))
753                                 cur_route = next_route;
754                         else if(!cur_route->get_tracks().count(entry_ep.track))
755                         {
756                                 // Keep the blocks if we arrived at the end of the route
757                                 good = last;
758                                 good_sens = nsens;
759                                 end_of_route = true;
760                                 break;
761                         }
762                 }
763                 else if(route && route->get_tracks().count(entry_ep.track))
764                         cur_route = route;
765
766                 if(link->get_endpoints().size()<2)
767                 {
768                         good = last;
769                         good_sens = nsens;
770                         break;
771                 }
772
773                 bool reserved = link->reserve(this);
774                 if(!reserved)
775                 {
776                         // Ask a lesser priority train to free the block for us
777                         if(link->get_train()->get_priority()<priority)
778                                 if(link->get_train()->free_block(*link))
779                                         reserved = link->reserve(this);
780
781                         if(!reserved)
782                         {
783                                 // If we found another train and it's not headed straight for us, we can keep the blocks we got
784                                 int other_entry = link->get_train()->get_entry_to_block(*link);
785                                 if(other_entry<0)
786                                         throw LogicError("Block reservation inconsistency");
787                                 if(static_cast<unsigned>(entry)!=link->traverse(other_entry))
788                                 {
789                                         good = last;
790                                         good_sens = nsens;
791                                 }
792                                 pending_block = link;
793                                 break;
794                         }
795                 }
796
797                 if(link->get_turnout_id())
798                 {
799                         const Endpoint &track_ep = entry_ep.track->get_type().get_endpoints()[entry_ep.track_ep];
800
801                         // Keep the blocks reserved so far, as either us or the other train can diverge
802                         good = last;
803                         good_sens = nsens;
804
805                         // Figure out what path we'd like to take on the turnout
806                         int path = -1;
807                         if(cur_route)
808                                 path = cur_route->get_turnout(link->get_turnout_id());
809                         if(path<0)
810                                 path = entry_ep.track->get_active_path();
811                         if(!((track_ep.paths>>path)&1))
812                         {
813                                 for(unsigned i=0; track_ep.paths>>i; ++i)
814                                         if((track_ep.paths>>i)&1)
815                                                 path = i;
816                         }
817
818                         if(path!=static_cast<int>(entry_ep.track->get_active_path()))
819                         {
820                                 // The turnout is set to wrong path - switch and wait for it
821                                 pending_block = link;
822                                 entry_ep.track->set_active_path(path);
823                                 if(pending_block)
824                                 {
825                                         link->reserve(0);
826                                         break;
827                                 }
828                         }
829                 }
830
831                 rsv_blocks.push_back(BlockRef(link, entry));
832                 last = &rsv_blocks.back();
833                 if(last->block->get_sensor_id())
834                 {
835                         ++nsens;
836                         got_more = true;
837                 }
838         }
839
840         // Unreserve blocks that were not good
841         while(!rsv_blocks.empty() && last!=good)
842         {
843                 last->block->reserve(0);
844                 rsv_blocks.erase(--rsv_blocks.end());
845                 if(!rsv_blocks.empty())
846                         last = &rsv_blocks.back();
847         }
848
849         reserving = false;
850
851         // Make any sensorless blocks at the beginning immediately current
852         list<BlockRef>::iterator i;
853         for(i=rsv_blocks.begin(); (i!=rsv_blocks.end() && !i->block->get_sensor_id()); ++i) ;
854         if(i!=rsv_blocks.begin())
855                 cur_blocks.splice(cur_blocks.end(), rsv_blocks, rsv_blocks.begin(), i);
856
857         return good_sens;
858 }
859
860 float Train::get_real_speed(unsigned i) const
861 {
862         if(real_speed[i].weight)
863                 return real_speed[i].speed;
864
865         unsigned low;
866         unsigned high;
867         for(low=i; low>0; --low)
868                 if(real_speed[low].weight)
869                         break;
870         for(high=i; high<14; ++high)
871                 if(real_speed[high].weight)
872                         break;
873
874         if(real_speed[high].weight)
875         {
876                 if(real_speed[low].weight)
877                 {
878                         float f = float(i-low)/(high-low);
879                         return real_speed[low].speed*(1-f)+real_speed[high].speed*f;
880                 }
881                 else
882                         return real_speed[high].speed*float(i)/high;
883         }
884         else if(real_speed[low].weight)
885                 return real_speed[low].speed*float(i)/low;
886         else
887                 return 0;
888 }
889
890 unsigned Train::find_speed(float real) const
891 {
892         if(real<=real_speed[0].speed)
893                 return 0;
894
895         unsigned low = 0;
896         unsigned high = 0;
897         for(unsigned i=0; (!high && i<=14); ++i)
898                 if(real_speed[i].weight)
899                 {
900                         if(real_speed[i].speed<real)
901                                 low = i;
902                         else
903                                 high = i;
904                 }
905         if(!high)
906         {
907                 if(!low)
908                 {
909                         if(real)
910                                 return 3;
911                         else
912                                 return 0;
913                 }
914                 return min(static_cast<unsigned>(low*real/real_speed[low].speed), 14U);
915         }
916
917         float f = (real-real_speed[low].speed)/(real_speed[high].speed-real_speed[low].speed);
918         return static_cast<unsigned>(low*(1-f)+high*f+0.5);
919 }
920
921 float Train::get_travel_speed() const
922 {
923         float speed = get_real_speed(current_speed);
924         float scale = layout.get_catalogue().get_scale();
925         return static_cast<int>(round(speed/scale*3.6/5))*5;
926 }
927
928 void Train::set_status(const string &s)
929 {
930         status = s;
931         signal_status_changed.emit(s);
932 }
933
934 void Train::release_blocks(list<BlockRef> &blocks)
935 {
936         release_blocks(blocks, blocks.begin(), blocks.end());
937 }
938
939 void Train::release_blocks(list<BlockRef> &blocks, list<BlockRef>::iterator begin, list<BlockRef>::iterator end)
940 {
941         while(begin!=end)
942         {
943                 Block *block = begin->block;
944                 blocks.erase(begin++);
945                 block->reserve(0);
946         }
947 }
948
949 void Train::reverse_blocks(list<BlockRef> &blocks) const
950 {
951         blocks.reverse();
952         for(list<BlockRef>::iterator i=blocks.begin(); i!=blocks.end(); ++i)
953                 i->entry = i->block->traverse(i->entry);
954 }
955
956
957 Train::BlockRef::BlockRef(Block *b, unsigned e):
958         block(b),
959         entry(e)
960 { }
961
962 Train::BlockRef Train::BlockRef::next() const
963 {
964         Block *blk = block->get_endpoints()[block->traverse(entry)].link;
965         if(!blk)
966                 throw InvalidState("At end of line");
967
968         int ep = blk->get_endpoint_by_link(*block);
969         if(ep<0)
970                 throw LogicError("Block links are inconsistent");
971
972         return BlockRef(blk, ep);
973 }
974
975
976 Train::RealSpeed::RealSpeed():
977         speed(0),
978         weight(0)
979 { }
980
981 void Train::RealSpeed::add(float s, float w)
982 {
983         speed = (speed*weight+s*w)/(weight+w);
984         weight = min(weight+w, 300.0f);
985 }
986
987
988 Train::Loader::Loader(Train &t):
989         DataFile::BasicLoader<Train>(t),
990         prev_block(0),
991         blocks_valid(true)
992 {
993         add("block",       &Loader::block);
994         add("block_hint",  &Loader::block_hint);
995         add("name",        &Loader::name);
996         add("priority",    &Train::priority);
997         add("real_speed",  &Loader::real_speed);
998         add("route",       &Loader::route);
999         add("timetable",   &Loader::timetable);
1000         add("vehicle",     &Loader::vehicle);
1001 }
1002
1003 void Train::Loader::finish()
1004 {
1005         if(!obj.cur_blocks.empty())
1006         {
1007                 const BlockRef &blkref = obj.cur_blocks.front();
1008                 const Block::Endpoint &bep = blkref.block->get_endpoints()[blkref.entry];
1009                 obj.vehicles.back()->place(bep.track, bep.track_ep, 0, Vehicle::BACK_BUFFER);
1010
1011                 obj.set_status("Stopped");
1012         }
1013 }
1014
1015 void Train::Loader::block(unsigned id)
1016 {
1017         if(!blocks_valid)
1018                 return;
1019
1020         Block *blk;
1021         try
1022         {
1023                 blk = &obj.layout.get_block(id);
1024         }
1025         catch(const KeyError &)
1026         {
1027                 blocks_valid = false;
1028                 return;
1029         }
1030
1031         int entry = -1;
1032         if(prev_block)
1033                 entry = blk->get_endpoint_by_link(*prev_block);
1034         if(entry<0)
1035                 entry = 0;
1036
1037         blk->reserve(&obj);
1038         obj.cur_blocks.push_back(BlockRef(blk, entry));
1039
1040         if(blk->get_sensor_id())
1041                 obj.layout.get_driver().set_sensor(blk->get_sensor_id(), true);
1042
1043         prev_block = blk;
1044 }
1045
1046 void Train::Loader::block_hint(unsigned id)
1047 {
1048         try
1049         {
1050                 prev_block = &obj.layout.get_block(id);
1051         }
1052         catch(const KeyError &)
1053         {
1054                 blocks_valid = false;
1055         }
1056 }
1057
1058 void Train::Loader::name(const string &n)
1059 {
1060         obj.set_name(n);
1061 }
1062
1063 void Train::Loader::real_speed(unsigned i, float speed, float weight)
1064 {
1065         obj.real_speed[i].speed = speed;
1066         obj.real_speed[i].weight = weight;
1067 }
1068
1069 void Train::Loader::route(const string &n)
1070 {
1071         obj.set_route(&obj.layout.get_route(n));
1072 }
1073
1074 void Train::Loader::timetable()
1075 {
1076         if(obj.timetable)
1077                 throw InvalidState("A timetable has already been loaded");
1078
1079         obj.timetable = new Timetable(obj);
1080         load_sub(*obj.timetable);
1081 }
1082
1083 void Train::Loader::vehicle(unsigned n)
1084 {
1085         const VehicleType &vtype = obj.layout.get_catalogue().get_vehicle(n);
1086         Vehicle *veh = new Vehicle(obj.layout, vtype);
1087         obj.vehicles.back()->attach_back(*veh);
1088         obj.vehicles.push_back(veh);
1089 }
1090
1091 } // namespace Marklin