]> git.tdb.fi Git - r2c2.git/blob - source/libmarklin/train.cpp
Add a variant of Route::find that takes a set of tracks
[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 {
28
29 struct SetFlag
30 {
31         bool &flag;
32
33         SetFlag(bool &f): flag(f) { flag = true; }
34         ~SetFlag() { flag = false; }
35 };
36
37 }
38
39
40 namespace Marklin {
41
42 Train::Train(Layout &l, const VehicleType &t, unsigned a):
43         layout(l),
44         loco_type(t),
45         address(a),
46         priority(0),
47         yielding_to(0),
48         pending_block(0),
49         reserving(false),
50         advancing(false),
51         controller(new AIControl(*this, new SimpleController)),
52         timetable(0),
53         active(false),
54         current_speed(0),
55         speed_changing(false),
56         reverse(false),
57         functions(0),
58         end_of_route(false),
59         status("Unplaced"),
60         travel_dist(0),
61         pure_speed(false),
62         real_speed(15),
63         accurate_position(false),
64         overshoot_dist(false)
65 {
66         if(!loco_type.is_locomotive())
67                 throw InvalidParameterValue("Initial vehicle must be a locomotive");
68
69         vehicles.push_back(new Vehicle(layout, loco_type));
70
71         layout.add_train(*this);
72
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));
76
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));
80
81         layout.get_driver().signal_halt.connect(sigc::mem_fun(this, &Train::halt_event));
82
83         controller->signal_control_changed.connect(sigc::mem_fun(this, &Train::control_changed));
84 }
85
86 Train::~Train()
87 {
88         delete controller;
89         delete timetable;
90         for(vector<Vehicle *>::iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
91                 delete *i;
92         layout.remove_train(*this);
93 }
94
95 void Train::set_name(const string &n)
96 {
97         name = n;
98
99         signal_name_changed.emit(name);
100 }
101
102 void Train::set_priority(int p)
103 {
104         priority = p;
105 }
106
107 void Train::yield_to(const Train &t)
108 {
109         yielding_to = &t;
110 }
111
112 void Train::add_vehicle(const VehicleType &vt)
113 {
114         Vehicle *veh = new Vehicle(layout, vt);
115         vehicles.back()->attach_back(*veh);
116         vehicles.push_back(veh);
117 }
118
119 void Train::remove_vehicle(unsigned i)
120 {
121         if(i>=vehicles.size())
122                 throw InvalidParameterValue("Vehicle index out of range");
123         if(i==0)
124                 throw InvalidParameterValue("Can't remove the locomotive");
125         delete vehicles[i];
126         vehicles.erase(vehicles.begin()+i);
127         if(i<vehicles.size())
128                 vehicles[i-1]->attach_back(*vehicles[i]);
129 }
130
131 unsigned Train::get_n_vehicles() const
132 {
133         return vehicles.size();
134 }
135
136 Vehicle &Train::get_vehicle(unsigned i)
137 {
138         if(i>=vehicles.size())
139                 throw InvalidParameterValue("Vehicle index out of range");
140         return *vehicles[i];
141 }
142
143 const Vehicle &Train::get_vehicle(unsigned i) const
144 {
145         if(i>=vehicles.size())
146                 throw InvalidParameterValue("Vehicle index out of range");
147         return *vehicles[i];
148 }
149
150 void Train::set_control(const string &n, float v)
151 {
152         controller->set_control(n, v);
153 }
154
155 void Train::set_active(bool a)
156 {
157         if(a==active)
158                 return;
159         if(!a && controller->get_speed())
160                 throw InvalidState("Can't deactivate while moving");
161
162         active = a;
163         if(active)
164         {
165                 stop_timeout = Time::TimeStamp();
166                 reserve_more();
167         }
168         else
169         {
170                 stop_timeout = Time::now()+2*Time::sec;
171                 set_status("Stopped");
172         }
173 }
174
175 void Train::set_function(unsigned func, bool state)
176 {
177         if(!loco_type.get_functions().count(func))
178                 throw InvalidParameterValue("Invalid function");
179         if(func<5)
180                 layout.get_driver().set_loco_function(address, func, state);
181         else
182                 layout.get_driver().set_loco_function(address+1, func-4, state);
183 }
184
185 float Train::get_control(const string &ctrl) const
186 {
187         return controller->get_control(ctrl).value;
188 }
189
190 float Train::get_speed() const
191 {
192         return controller->get_speed();
193 }
194
195 bool Train::get_function(unsigned func) const
196 {
197         return (functions>>func)&1;
198 }
199
200 void Train::set_timetable(Timetable *tt)
201 {
202         delete timetable;
203         timetable = tt;
204 }
205
206 void Train::set_route(const Route *r)
207 {
208         free_noncritical_blocks();
209
210         routes.clear();
211         if(r)
212                 routes.push_back(r);
213         end_of_route = false;
214
215         if(r && !cur_blocks.empty())
216         {
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));
222
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());
226         }
227
228         reserve_more();
229
230         signal_route_changed.emit(get_route());
231 }
232
233 void Train::go_to(const Track &to)
234 {
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)))
237                 {
238                         signal_arrived.emit();
239                         set_route(0);
240                         return;
241                 }
242
243         free_noncritical_blocks();
244
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];
248
249         set_route(Route::find(*ep.track, ep.track_ep, to));
250 }
251
252 bool Train::divert(Track &from)
253 {
254         if(!from.get_turnout_id())
255                 throw InvalidParameterValue("Can't divert from a non-turnout");
256         if(routes.empty())
257                 return false;
258
259         int path = -1;
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;
265
266         // Follow our routes to find out where we're entering the turnout
267         while(1)
268         {
269                 Block *link = block->get_link(block->traverse(entry, route->route));
270                 entry = link->get_endpoint_by_link(*block);
271                 block = link;
272
273                 const Block::Endpoint &entry_ep = block->get_endpoints()[entry];
274
275                 if(visited.count(entry_ep.track))
276                         return false;
277                 visited.insert(entry_ep.track);
278
279                 if(!advance_route(route, *entry_ep.track))
280                         return false;
281
282                 if(entry_ep.track==&from)
283                 {
284                         if(block->get_train()==this && !free_block(*block))
285                                 return false;
286
287                         from_ep = entry_ep.track_ep;
288                         path = route->route->get_turnout(from.get_turnout_id());
289                         break;
290                 }
291         }
292
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)))
296                 return false;
297
298         // Choose some other path
299         for(int i=0; ep_paths>>i; ++i)
300                 if((ep_paths&(1<<i)) && i!=path)
301                 {
302                         path = i;
303                         break;
304                 }
305
306         Track *track = from.get_link(from.traverse(from_ep, path));
307         if(!track)
308                 return false;
309
310         unsigned ep = track->get_endpoint_by_link(from);
311
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;
316         try
317         {
318                 diversion = Route::find(*track, ep, tracks);
319         }
320         catch(const Msp::Exception &)
321         {
322                 return false;
323         }
324
325         diversion->set_name("Diversion");
326         diversion->add_track(from);
327         diversion->set_turnout(from.get_turnout_id(), path);
328
329         if(!is_valid_diversion(*diversion, from, from_ep))
330         {
331                 delete diversion;
332                 return false;
333         }
334
335         // Follow the diversion route until we get back to the original route
336         list<RouteRef>::iterator end = routes.end();
337         while(1)
338         {
339                 path = 0;
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));
343
344                 for(list<RouteRef>::iterator i=route; (end==routes.end() && i!=routes.end()); ++i)
345                         if(i->route->get_tracks().count(next))
346                                 end = i;
347
348                 if(end!=routes.end())
349                         break;
350                 else if(!diversion->get_tracks().count(next))
351                         throw Exception("Pathfinder returned a bad route");
352
353                 ep = next->get_endpoint_by_link(*track);
354                 track = next;
355         }
356
357         if(route==end)
358                 // We are rejoining the same route we diverted from, duplicate it
359                 routes.insert(end, *route);
360         else
361         {
362                 ++route;
363                 routes.erase(route, end);
364         }
365         routes.insert(end, RouteRef(diversion, from.get_turnout_id()));
366
367         return true;
368 }
369
370 const Route *Train::get_route() const
371 {
372         if(routes.empty())
373                 return 0;
374         return routes.front().route;
375 }
376
377 void Train::place(Block &block, unsigned entry)
378 {
379         if(controller->get_speed())
380                 throw InvalidState("Must be stopped before placing");
381
382         release_blocks(rsv_blocks);
383         release_blocks(cur_blocks);
384
385         set_active(false);
386         accurate_position = false;
387
388         if(!block.reserve(this))
389         {
390                 set_status("Unplaced");
391                 return;
392         }
393
394         cur_blocks.push_back(BlockRef(&block, entry));
395         if(reverse)
396         {
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);
402         }
403         else
404         {
405                 const Block::Endpoint &bep = block.get_endpoints()[entry];
406                 vehicles.back()->place(*bep.track, bep.track_ep, 0, Vehicle::BACK_BUFFER);
407         }
408 }
409
410 void Train::unplace()
411 {
412         if(controller->get_speed())
413                 throw InvalidState("Must be stopped before unplacing");
414
415         release_blocks(rsv_blocks);
416         release_blocks(cur_blocks);
417
418         set_active(false);
419         accurate_position = false;
420
421         for(vector<Vehicle *>::iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
422                 (*i)->unplace();
423
424         set_status("Unplaced");
425 }
426
427 bool Train::free_block(Block &block)
428 {
429         float margin = 10*layout.get_catalogue().get_scale();
430         if(get_reserved_distance_until(&block, false)<controller->get_braking_distance()*1.3+margin)
431                 return false;
432
433         unsigned nsens = 0;
434         for(list<BlockRef>::iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
435         {
436                 if(i->block==&block)
437                 {
438                         if(nsens<1)
439                                 return false;
440                         release_blocks(rsv_blocks, i, rsv_blocks.end());
441                         return true;
442                 }
443                 else if(i->block->get_sensor_id())
444                         ++nsens;
445         }
446
447         return false;
448 }
449
450 void Train::free_noncritical_blocks()
451 {
452         if(cur_blocks.empty() || rsv_blocks.empty())
453                 return;
454
455         if(controller->get_speed()==0)
456         {
457                 release_blocks(rsv_blocks);
458                 return;
459         }
460
461         float margin = 10*layout.get_catalogue().get_scale();
462         float min_dist = controller->get_braking_distance()*1.3+margin;
463
464         Vehicle &veh = *(reverse ? vehicles.back() : vehicles.front());
465
466         Track *track = veh.get_track();
467         list<BlockRef>::iterator block = cur_blocks.begin();
468         bool in_rsv = false;
469         while(block!=rsv_blocks.end() && !block->block->get_tracks().count(track))
470         {
471                 ++block;
472                 if(block==cur_blocks.end())
473                 {
474                         block = rsv_blocks.begin();
475                         in_rsv = true;
476                 }
477         }
478
479         unsigned entry = veh.get_entry();
480         float dist = veh.get_offset();
481         if(reverse)
482                 entry = track->traverse(entry);
483         else
484                 dist = track->get_type().get_path_length(track->get_active_path())-dist;
485         dist -= veh.get_type().get_length()/2;
486
487         bool nsens = 0;
488         while(1)
489         {
490                 Track *next = track->get_link(track->traverse(entry));
491                 entry = next->get_endpoint_by_link(*track);
492                 track = next;
493
494                 if(!block->block->get_tracks().count(track))
495                 {
496                         ++block;
497                         if(block==cur_blocks.end())
498                         {
499                                 block = rsv_blocks.begin();
500                                 in_rsv = true;
501                         }
502                         if(block==rsv_blocks.end())
503                                 return;
504
505                         if(dist>min_dist && nsens>0)
506                         {
507                                 release_blocks(rsv_blocks, block, rsv_blocks.end());
508                                 return;
509                         }
510
511                         if(in_rsv && block->block->get_sensor_id())
512                                 ++nsens;
513                 }
514
515                 dist += track->get_type().get_path_length(track->get_active_path());
516         }
517 }
518
519 int Train::get_entry_to_block(Block &block) const
520 {
521         for(list<BlockRef>::const_iterator i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
522                 if(i->block==&block)
523                         return i->entry;
524         for(list<BlockRef>::const_iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
525                 if(i->block==&block)
526                         return i->entry;
527         return -1;
528 }
529
530 float Train::get_reserved_distance() const
531 {
532         return get_reserved_distance_until(0, false);
533 }
534
535 void Train::tick(const Time::TimeStamp &t, const Time::TimeDelta &dt)
536 {
537         if(!active && stop_timeout && t>=stop_timeout)
538         {
539                 release_blocks(rsv_blocks);
540                 end_of_route = false;
541                 stop_timeout = Time::TimeStamp();
542         }
543
544         Driver &driver = layout.get_driver();
545
546         if(timetable)
547                 timetable->tick(t);
548         controller->tick(dt);
549         float speed = controller->get_speed();
550         unsigned speed_notch = find_speed(speed);
551
552         if(controller->get_reverse()!=reverse)
553         {
554                 reverse = controller->get_reverse();
555                 driver.set_loco_reverse(address, reverse);
556
557                 release_blocks(rsv_blocks);
558                 reverse_blocks(cur_blocks);
559
560                 reserve_more();
561         }
562         if(speed_notch!=current_speed && !speed_changing && !driver.is_halted() && driver.get_power())
563         {
564                 speed_changing = true;
565                 driver.set_loco_speed(address, speed_notch);
566
567                 pure_speed = false;
568
569                 if(speed_notch)
570                         set_status(format("Traveling %d kmh", get_travel_speed()));
571                 else
572                         set_status("Waiting");
573         }
574
575         if(speed)
576         {
577                 if(!active)
578                         set_active(true);
579
580                 Vehicle &vehicle = *(reverse ? vehicles.back() : vehicles.front());
581                 Track *track = vehicle.get_track();
582
583                 bool ok = false;
584                 for(list<BlockRef>::const_iterator i=cur_blocks.begin(); (!ok && i!=cur_blocks.end()); ++i)
585                         ok = i->block->get_tracks().count(track);
586
587                 float d = get_real_speed(current_speed)*(dt/Time::sec);
588                 if(ok)
589                 {
590                         SetFlag setf(advancing);
591                         vehicle.advance(reverse ? -d : d);
592                 }
593                 else if(accurate_position)
594                 {
595                         overshoot_dist += d;
596                         if(overshoot_dist>40*layout.get_catalogue().get_scale())
597                         {
598                                 layout.emergency(name+" has not arrived at sensor");
599                                 accurate_position = false;
600                         }
601                 }
602         }
603         else if(end_of_route && rsv_blocks.empty())
604         {
605                 set_active(false);
606                 signal_arrived.emit();
607                 set_route(0);
608         }
609
610         if(!cur_blocks.empty() && !cur_blocks.front().block->get_sensor_id())
611         {
612                 float dist = get_reserved_distance_until(cur_blocks.front().block, true);
613
614                 if(dist>10*layout.get_catalogue().get_scale())
615                 {
616                         cur_blocks.front().block->reserve(0);
617                         cur_blocks.pop_front();
618                 }
619         }
620 }
621
622 void Train::save(list<DataFile::Statement> &st) const
623 {
624         st.push_back((DataFile::Statement("name"), name));
625
626         st.push_back((DataFile::Statement("priority"), priority));
627
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()));
631
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));
635
636         if(!cur_blocks.empty())
637         {
638                 list<BlockRef> blocks = cur_blocks;
639                 if(reverse)
640                         reverse_blocks(blocks);
641
642                 Block *prev = blocks.front().block->get_endpoints()[blocks.front().entry].link;
643                 st.push_back((DataFile::Statement("block_hint"), prev->get_id()));
644
645                 for(list<BlockRef>::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
646                         st.push_back((DataFile::Statement("block"), i->block->get_id()));
647         }
648
649         if(!routes.empty())
650         {
651                 list<RouteRef>::const_iterator i = routes.begin();
652                 for(; (i!=routes.end() && i->route->is_temporary()); ++i) ;
653                 if(i!=routes.end())
654                         st.push_back((DataFile::Statement("route"), i->route->get_name()));
655         }
656
657         if(timetable)
658         {
659                 DataFile::Statement ss("timetable");
660                 timetable->save(ss.sub);
661                 st.push_back(ss);
662         }
663 }
664
665 void Train::control_changed(const Controller::Control &ctrl)
666 {
667         signal_control_changed.emit(ctrl.name, ctrl.value);
668 }
669
670 void Train::loco_speed_event(unsigned addr, unsigned speed, bool)
671 {
672         if(addr==address)
673         {
674                 current_speed = speed;
675                 speed_changing = false;
676                 pure_speed = false;
677         }
678 }
679
680 void Train::loco_func_event(unsigned addr, unsigned func, bool state)
681 {
682         if(addr==address || (addr==address+1 && loco_type.get_max_function()>4))
683         {
684                 if(addr==address+1)
685                         func += 4;
686                 if(state)
687                         functions |= 1<<func;
688                 else
689                         functions &= ~(1<<func);
690
691                 signal_function_changed.emit(func, state);
692         }
693 }
694
695 void Train::sensor_event(unsigned addr, bool state)
696 {
697         if(state)
698         {
699                 // Find the first sensor block from our reserved blocks that isn't this sensor
700                 list<BlockRef>::iterator i;
701                 unsigned result = 0;
702                 for(i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
703                         if(i->block->get_sensor_id())
704                         {
705                                 if(i->block->get_sensor_id()!=addr)
706                                 {
707                                         if(result==0)
708                                                 result = 2;
709                                         else if(result==1)
710                                                 break;
711                                 }
712                                 else if(result==0)
713                                         result = 1;
714                                 else if(result==2)
715                                         result = 3;
716                         }
717
718                 if(result==1 && i!=rsv_blocks.begin())
719                 {
720                         // Compute speed and update related state
721                         float travel_time_secs = (Time::now()-last_entry_time)/Time::sec;
722
723                         if(pure_speed)
724                         {
725                                 if(current_speed)
726                                 {
727                                         RealSpeed &rs = real_speed[current_speed];
728                                         rs.add(travel_dist/travel_time_secs, travel_time_secs);
729                                 }
730                                 set_status(format("Traveling %d kmh", get_travel_speed()));
731                         }
732
733                         travel_dist = 0;
734                         float block_len;
735                         for(list<BlockRef>::iterator j=rsv_blocks.begin(); j!=i; ++j)
736                         {
737                                 j->block->traverse(j->entry, &block_len);
738                                 travel_dist += block_len;
739
740                                 if(j->block->get_sensor_id()==addr && !advancing)
741                                 {
742                                         const Block::Endpoint &bep = j->block->get_endpoints()[j->entry];
743                                         if(reverse)
744                                         {
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);
748                                         }
749                                         else
750                                                 vehicles.front()->place(*bep.track, bep.track_ep, 0, Vehicle::FRONT_AXLE);
751                                 }
752                         }
753                         last_entry_time = Time::now();
754                         pure_speed = true;
755                         accurate_position = true;
756                         overshoot_dist = 0;
757
758                         // Check if we've reached the next route
759                         if(routes.size()>1)
760                         {
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))
764                                         {
765                                                 routes.pop_front();
766                                                 // XXX Exceptions?
767                                                 signal_route_changed.emit(routes.front().route);
768                                                 break;
769                                         }
770                         }
771
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);
774
775                         // Try to get more blocks if we're moving
776                         if(active)
777                                 reserve_more();
778                 }
779                 else if(result==3)
780                         layout.emergency("Sensor for "+name+" triggered out of order");
781         }
782         else
783         {
784                 const Vehicle &veh = *(reverse ? vehicles.front() : vehicles.back());
785
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)
789                 {
790                         if(i->block->get_tracks().count(veh.get_track()))
791                                 break;
792                         if(i->block->get_sensor_id())
793                         {
794                                 if(layout.get_driver().get_sensor(i->block->get_sensor_id()))
795                                         break;
796                                 else
797                                 {
798                                         end = i;
799                                         ++end;
800                                 }
801                         }
802                 }
803                 
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);
807         }
808 }
809
810 void Train::turnout_event(unsigned addr, bool)
811 {
812         if(pending_block && (!pending_block->get_train() || pending_block->get_train()==this))
813         {
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))
817                 {
818                         if(reserving)
819                                 pending_block = 0;
820                         else
821                                 reserve_more();
822                 }
823         }
824 }
825
826 void Train::halt_event(bool h)
827 {
828         if(h)
829                 accurate_position = false;
830 }
831
832 void Train::block_reserved(const Block &block, const Train *train)
833 {
834         if(&block==pending_block && !train && !reserving)
835                 reserve_more();
836 }
837
838 unsigned Train::reserve_more()
839 {
840         if(!active)
841                 return 0;
842
843         BlockRef *start = 0;
844         if(!rsv_blocks.empty())
845                 start = &rsv_blocks.back();
846         else if(!cur_blocks.empty())
847                 start = &cur_blocks.back();
848         if(!start)
849                 return 0;
850
851         pending_block = 0;
852
853         // See how many sensor blocks and how much track we already have
854         unsigned nsens = 0;
855         float dist = 0;
856         for(list<BlockRef>::const_iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
857         {
858                 if(i->block->get_sensor_id())
859                         ++nsens;
860                 if(nsens>0)
861                 {
862                         float length = 0;
863                         i->block->traverse(i->entry, &length);
864                         dist += length;
865                 }
866         }
867         
868         if(end_of_route)
869                 return nsens;
870
871         list<RouteRef>::iterator cur_route = routes.begin();
872         advance_route(cur_route, *start->block->get_endpoints()[start->entry].track);
873
874         float approach_margin = 50*layout.get_catalogue().get_scale();
875         float min_dist = controller->get_braking_distance()*1.3+approach_margin*2;
876
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;
885
886         SetFlag setf(reserving);
887
888         while(good_sens<3 || good_dist<min_dist || !contested_blocks.empty())
889         {
890                 // Traverse to the next block
891                 float length = 0;
892                 Block *link = 0;
893                 {
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);
897                 }
898                 if(!link)
899                         break;
900
901                 int entry = link->get_endpoint_by_link(*last->block);
902                 if(entry<0)
903                         throw LogicError("Block links are inconsistent!");
904
905                 const Block::Endpoint &entry_ep = link->get_endpoints()[entry];
906
907                 if(cur_route!=routes.end())
908                 {
909                         if(!advance_route(cur_route, *entry_ep.track))
910                         {
911                                 // Keep the blocks if we arrived at the end of the route
912                                 if(!blocking_train)
913                                 {
914                                         good = last;
915                                         good_sens = nsens;
916                                         good_dist = dist;
917                                         end_of_route = true;
918                                 }
919                                 break;
920                         }
921                 }
922                 else if(!routes.empty() && routes.front().route->get_tracks().count(entry_ep.track))
923                         cur_route = routes.begin();
924
925                 if(link->get_endpoints().size()<2)
926                 {
927                         if(!blocking_train)
928                         {
929                                 good = last;
930                                 good_sens = nsens;
931                                 good_dist = dist;
932                         }
933                         break;
934                 }
935
936                 if(blocking_train)
937                 {
938                         if(link->get_train()!=blocking_train)
939                         {
940                                 if(blocking_train->free_block(*contested_blocks.back().block))
941                                 {
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);
948                                         blocking_train = 0;
949                                         continue;
950                                 }
951                                 else
952                                 {
953                                         yield_to(*blocking_train);
954                                         pending_block = contested_blocks.front().block;
955                                         try_divert = divert_track;
956                                         break;
957                                 }
958                         }
959                         else
960                         {
961                                 contested_blocks.push_back(BlockRef(link, entry));
962                                 last = &contested_blocks.back();
963                                 continue;
964                         }
965                 }
966
967                 bool reserved = link->reserve(this);
968                 if(!reserved)
969                 {
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
973                         same direction. */
974                         Train *other_train = link->get_train();
975                         int other_entry = other_train->get_entry_to_block(*link);
976                         if(other_entry<0)
977                                 throw LogicError("Block reservation inconsistency");
978
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())
982                         {
983                                 /* The other train is not coming to the blocks we're holding, so we
984                                 can keep them. */
985                                 good = last;
986                                 good_sens = nsens;
987                                 good_dist = dist;
988                         }
989
990                         int other_prio = other_train->get_priority();
991
992                         if(!entry_conflict && !exit_conflict && other_prio<priority)
993                         {
994                                 /* Ask a lesser priority train going to the same direction to free
995                                 the block for us */
996                                 if(other_train->free_block(*link))
997                                         reserved = link->reserve(this);
998                         }
999                         else if(other_train!=yielding_to && (other_prio<priority || (other_prio==priority && entry_conflict)))
1000                         {
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();
1007                                 continue;
1008                         }
1009                         else if(divert_track && (entry_conflict || exit_conflict))
1010                                 // We are blocked, but there's a diversion possibility
1011                                 try_divert = true;
1012
1013                         if(!reserved)
1014                         {
1015                                 pending_block = link;
1016                                 break;
1017                         }
1018                 }
1019
1020                 if(link->get_turnout_id())
1021                 {
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));
1024
1025                         if(multiple_paths || !last->block->get_turnout_id())
1026                         {
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. */
1031                                 good = last;
1032                                 good_sens = nsens;
1033                                 good_dist = dist;
1034                         }
1035
1036                         // Figure out what path we'd like to take on the turnout
1037                         int path = -1;
1038                         for(list<RouteRef>::iterator i=cur_route; (path<0 && i!=routes.end()); ++i)
1039                                 path = i->route->get_turnout(link->get_turnout_id());
1040                         if(path<0)
1041                                 path = entry_ep.track->get_active_path();
1042                         if(!(track_ep.paths&(1<<path)))
1043                         {
1044                                 for(unsigned i=0; track_ep.paths>>i; ++i)
1045                                         if(track_ep.paths&(1<<i))
1046                                                 path = i;
1047                         }
1048
1049                         if(path!=static_cast<int>(entry_ep.track->get_active_path()))
1050                         {
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);
1054                                 if(pending_block)
1055                                 {
1056                                         link->reserve(0);
1057                                         break;
1058                                 }
1059                         }
1060
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;
1065                 }
1066
1067                 if(!contested_blocks.empty() && contested_blocks.front().block==link)
1068                         contested_blocks.pop_front();
1069
1070                 rsv_blocks.push_back(BlockRef(link, entry));
1071                 last = &rsv_blocks.back();
1072                 if(last->block->get_sensor_id())
1073                         ++nsens;
1074                 if(nsens>0)
1075                         dist += length;
1076         }
1077
1078         // Unreserve blocks that were not good
1079         while(!rsv_blocks.empty() && &rsv_blocks.back()!=good)
1080         {
1081                 rsv_blocks.back().block->reserve(0);
1082                 rsv_blocks.pop_back();
1083         }
1084
1085         if(!rsv_blocks.empty() && &rsv_blocks.back()!=start)
1086                 // We got some new blocks, so no longer need to yield
1087                 yielding_to = 0;
1088
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);
1094
1095         if(try_divert && divert(*divert_track))
1096                 return reserve_more();
1097
1098         return good_sens;
1099 }
1100
1101 float Train::get_reserved_distance_until(const Block *until_block, bool back) const
1102 {
1103         if(cur_blocks.empty())
1104                 return 0;
1105
1106         Vehicle &veh = *(reverse!=back ? vehicles.back() : vehicles.front());
1107         const VehicleType &vtype = veh.get_type();
1108
1109         Track *track = veh.get_track();
1110         if(!track)
1111                 return 0;
1112
1113         list<BlockRef>::const_iterator block = cur_blocks.begin();
1114         while(block!=rsv_blocks.end() && !block->block->get_tracks().count(track))
1115         {
1116                 ++block;
1117                 if(block==cur_blocks.end())
1118                 {
1119                         if(back)
1120                                 return 0;
1121                         block = rsv_blocks.begin();
1122                 }
1123         }
1124         if(block==rsv_blocks.end() || block->block==until_block)
1125                 return 0;
1126
1127         unsigned entry = veh.get_entry();
1128
1129         float result = veh.get_offset();
1130         if(reverse!=back)
1131                 entry = track->traverse(entry);
1132         else
1133                 result = track->get_type().get_path_length(track->get_active_path())-result;
1134         result -= vtype.get_length()/2;
1135
1136         while(1)
1137         {
1138                 if(track->get_type().get_endpoints().size()<2)
1139                         break;
1140
1141                 Track *next = track->get_link(track->traverse(entry));
1142
1143                 if(!block->block->get_tracks().count(next))
1144                 {
1145                         if(back)
1146                         {
1147                                 if(block==cur_blocks.begin())
1148                                         break;
1149                                 --block;
1150                         }
1151                         else
1152                         {
1153                                 ++block;
1154                                 if(block==cur_blocks.end())
1155                                         block = rsv_blocks.begin();
1156                                 if(block==rsv_blocks.end())
1157                                         break;
1158                         }
1159
1160                         if(block->block==until_block)
1161                                 break;
1162                 }
1163
1164                 entry = next->get_endpoint_by_link(*track);
1165                 track = next;
1166
1167                 result += track->get_type().get_path_length(track->get_active_path());
1168         }
1169
1170         return result;
1171 }
1172
1173 float Train::get_real_speed(unsigned i) const
1174 {
1175         if(real_speed[i].weight)
1176                 return real_speed[i].speed;
1177
1178         unsigned low;
1179         unsigned high;
1180         for(low=i; low>0; --low)
1181                 if(real_speed[low].weight)
1182                         break;
1183         for(high=i; high<14; ++high)
1184                 if(real_speed[high].weight)
1185                         break;
1186
1187         if(real_speed[high].weight)
1188         {
1189                 if(real_speed[low].weight)
1190                 {
1191                         float f = float(i-low)/(high-low);
1192                         return real_speed[low].speed*(1-f)+real_speed[high].speed*f;
1193                 }
1194                 else
1195                         return real_speed[high].speed*float(i)/high;
1196         }
1197         else if(real_speed[low].weight)
1198                 return real_speed[low].speed*float(i)/low;
1199         else
1200                 return 0;
1201 }
1202
1203 unsigned Train::find_speed(float real) const
1204 {
1205         if(real<=real_speed[0].speed)
1206                 return 0;
1207
1208         unsigned low = 0;
1209         unsigned high = 0;
1210         unsigned last = 0;
1211         for(unsigned i=0; (!high && i<=14); ++i)
1212                 if(real_speed[i].weight)
1213                 {
1214                         last = i;
1215                         if(real_speed[i].speed<real)
1216                                 low = i;
1217                         else
1218                                 high = i;
1219                 }
1220         if(!high)
1221         {
1222                 if(!low)
1223                 {
1224                         if(real)
1225                                 return 3;
1226                         else
1227                                 return 0;
1228                 }
1229                 return min(min(static_cast<unsigned>(low*real/real_speed[low].speed), 14U), last+3);
1230         }
1231
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);
1234 }
1235
1236 float Train::get_travel_speed() const
1237 {
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;
1241 }
1242
1243 void Train::set_status(const string &s)
1244 {
1245         status = s;
1246         signal_status_changed.emit(s);
1247 }
1248
1249 void Train::release_blocks(list<BlockRef> &blocks)
1250 {
1251         release_blocks(blocks, blocks.begin(), blocks.end());
1252 }
1253
1254 void Train::release_blocks(list<BlockRef> &blocks, list<BlockRef>::iterator begin, list<BlockRef>::iterator end)
1255 {
1256         while(begin!=end)
1257         {
1258                 Block *block = begin->block;
1259                 blocks.erase(begin++);
1260                 block->reserve(0);
1261         }
1262 }
1263
1264 void Train::reverse_blocks(list<BlockRef> &blocks) const
1265 {
1266         blocks.reverse();
1267         for(list<BlockRef>::iterator i=blocks.begin(); i!=blocks.end(); ++i)
1268                 i->entry = i->block->traverse(i->entry);
1269 }
1270
1271 bool Train::advance_route(list<RouteRef>::iterator &iter, const Track &track)
1272 {
1273         while(iter!=routes.end() && !iter->route->get_tracks().count(&track))
1274                 ++iter;
1275         if(iter==routes.end())
1276                 return false;
1277
1278         list<RouteRef>::iterator next = iter;
1279         ++next;
1280         if(next!=routes.end() && next->diversion && next->route->get_tracks().count(&track))
1281                 iter = next;
1282
1283         return true;
1284 }
1285
1286 Route *Train::create_lead_route()
1287 {
1288         Route *lead = new Route(layout);
1289         lead->set_name("Lead");
1290         lead->set_temporary(true);
1291
1292         for(list<BlockRef>::iterator i=cur_blocks.begin(); i!=rsv_blocks.end(); )
1293         {
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);
1298
1299                 if(++i==cur_blocks.end())
1300                         i = rsv_blocks.begin();
1301         }
1302
1303         return lead;
1304 }
1305
1306 bool Train::is_valid_diversion(const Route &diversion, const Track &from, unsigned from_ep)
1307 {
1308         float diversion_len = 0;
1309         const Track *track = &from;
1310         unsigned ep = from_ep;
1311         while(diversion.get_tracks().count(track))
1312         {
1313                 unsigned path = 0;
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);
1317
1318                 const Track *next = track->get_link(track->traverse(ep, path));
1319                 ep = next->get_endpoint_by_link(*track);
1320                 track = next;
1321
1322                 if(track==&from)
1323                         return false;
1324         }
1325
1326         list<RouteRef>::iterator route = routes.begin();
1327         if(!advance_route(route, from))
1328                 return false;
1329
1330         set<const Track *> visited;
1331         float route_len = 0;
1332         track = &from;
1333         ep = from_ep;
1334         while(1)
1335         {
1336                 unsigned path = 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);
1340
1341                 if(track!=&from && diversion.get_tracks().count(track))
1342                         break;
1343
1344                 if(visited.count(track))
1345                         return false;
1346                 visited.insert(track);
1347
1348                 const Track *next = track->get_link(track->traverse(ep, path));
1349                 ep = next->get_endpoint_by_link(*track);
1350                 track = next;
1351
1352                 if(!advance_route(route, *track))
1353                         return false;
1354         }
1355
1356         return diversion_len<route_len*1.2;
1357 }
1358
1359
1360 Train::BlockRef::BlockRef(Block *b, unsigned e):
1361         block(b),
1362         entry(e)
1363 { }
1364
1365 Train::BlockRef Train::BlockRef::next() const
1366 {
1367         Block *blk = block->get_endpoints()[block->traverse(entry)].link;
1368         if(!blk)
1369                 throw InvalidState("At end of line");
1370
1371         int ep = blk->get_endpoint_by_link(*block);
1372         if(ep<0)
1373                 throw LogicError("Block links are inconsistent");
1374
1375         return BlockRef(blk, ep);
1376 }
1377
1378
1379 Train::RouteRef::RouteRef(const Route *r, unsigned d):
1380         route(r),
1381         diversion(d)
1382 { }
1383
1384
1385 Train::RealSpeed::RealSpeed():
1386         speed(0),
1387         weight(0)
1388 { }
1389
1390 void Train::RealSpeed::add(float s, float w)
1391 {
1392         speed = (speed*weight+s*w)/(weight+w);
1393         weight = min(weight+w, 300.0f);
1394 }
1395
1396
1397 Train::Loader::Loader(Train &t):
1398         DataFile::BasicLoader<Train>(t),
1399         prev_block(0),
1400         blocks_valid(true)
1401 {
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);
1410 }
1411
1412 void Train::Loader::finish()
1413 {
1414         if(!obj.cur_blocks.empty())
1415         {
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);
1420
1421                 obj.set_status("Stopped");
1422         }
1423 }
1424
1425 void Train::Loader::block(unsigned id)
1426 {
1427         if(!blocks_valid)
1428                 return;
1429
1430         Block *blk;
1431         try
1432         {
1433                 blk = &obj.layout.get_block(id);
1434         }
1435         catch(const KeyError &)
1436         {
1437                 blocks_valid = false;
1438                 return;
1439         }
1440
1441         int entry = -1;
1442         if(prev_block)
1443                 entry = blk->get_endpoint_by_link(*prev_block);
1444         if(entry<0)
1445                 entry = 0;
1446
1447         blk->reserve(&obj);
1448         obj.cur_blocks.push_back(BlockRef(blk, entry));
1449
1450         if(blk->get_sensor_id())
1451                 obj.layout.get_driver().set_sensor(blk->get_sensor_id(), true);
1452
1453         prev_block = blk;
1454 }
1455
1456 void Train::Loader::block_hint(unsigned id)
1457 {
1458         try
1459         {
1460                 prev_block = &obj.layout.get_block(id);
1461         }
1462         catch(const KeyError &)
1463         {
1464                 blocks_valid = false;
1465         }
1466 }
1467
1468 void Train::Loader::name(const string &n)
1469 {
1470         obj.set_name(n);
1471 }
1472
1473 void Train::Loader::real_speed(unsigned i, float speed, float weight)
1474 {
1475         obj.real_speed[i].speed = speed;
1476         obj.real_speed[i].weight = weight;
1477 }
1478
1479 void Train::Loader::route(const string &n)
1480 {
1481         obj.set_route(&obj.layout.get_route(n));
1482 }
1483
1484 void Train::Loader::timetable()
1485 {
1486         if(obj.timetable)
1487                 throw InvalidState("A timetable has already been loaded");
1488
1489         obj.timetable = new Timetable(obj);
1490         load_sub(*obj.timetable);
1491 }
1492
1493 void Train::Loader::vehicle(unsigned n)
1494 {
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);
1499 }
1500
1501 } // namespace Marklin