]> git.tdb.fi Git - r2c2.git/blobdiff - source/libr2c2/departures.cpp
Add a dialog and necessary support code to display departures
[r2c2.git] / source / libr2c2 / departures.cpp
diff --git a/source/libr2c2/departures.cpp b/source/libr2c2/departures.cpp
new file mode 100644 (file)
index 0000000..d21cc94
--- /dev/null
@@ -0,0 +1,168 @@
+#include "departures.h"
+#include "layout.h"
+#include "timetable.h"
+#include "train.h"
+#include "trainrouter.h"
+#include "zone.h"
+
+using namespace std;
+using namespace Msp;
+
+namespace {
+
+bool departure_time_order(const R2C2::Departures::Departure &d1, const R2C2::Departures::Departure &d2)
+{
+       return d1.time<d2.time;
+}
+
+}
+
+
+namespace R2C2 {
+
+Departures::Departures(const Layout &layout, const string &group):
+       zones(layout.get_zones(group))
+{
+       const map<unsigned, Train *> &trains = layout.get_trains();
+       for(map<unsigned, Train *>::const_iterator i=trains.begin(); i!=trains.end(); ++i)
+       {
+               Timetable *timetable = i->second->get_ai_of_type<Timetable>();
+               (void)timetable;
+               TrainRouter *router = i->second->get_ai_of_type<TrainRouter>();
+               router->signal_route_changed.connect(sigc::bind(sigc::mem_fun(this, &Departures::train_route_changed), sigc::ref(*i->second)));
+               router->signal_departed.connect(sigc::bind(sigc::mem_fun(this, &Departures::train_departed), sigc::ref(*i->second)));
+
+               update_departures(*i->second);
+       }
+}
+
+void Departures::train_route_changed(const Route *, Train &train)
+{
+       update_departures(train);
+}
+
+void Departures::train_departed(Train &train)
+{
+       update_departures(train);
+}
+
+void Departures::update_departures(Train &train)
+{
+       const Clock &clock = train.get_layout().get_clock();
+       Time::TimeDelta t = clock.get_current_time();
+       float rate = clock.get_rate();
+
+       list<Departure> collected_departures;
+
+       Timetable *timetable = train.get_ai_of_type<Timetable>();
+       unsigned tt_length = timetable->get_length();
+       for(unsigned i=0; i<tt_length; ++i)
+       {
+               const Timetable::Row &row = timetable->get_row(i);
+               if(row.type==Timetable::DEPART)
+                       if(Zone *zone = get_attached_zone(*row.target))
+                       {
+                               Time::TimeDelta dt = row.time;
+                               while(dt<t)
+                                       dt += Time::day;
+                               collected_departures.push_back(Departure(*zone, train, dt));
+                       }
+       }
+
+       collected_departures.sort(departure_time_order);
+
+       TrainRouter *router = train.get_ai_of_type<TrainRouter>();
+       Time::TimeDelta departure_delay = router->get_departure_delay();
+       if(departure_delay)
+               if(Zone *zone = get_attached_zone(*train.get_block_allocator().last()))
+               {
+                       Departure dep(*zone, train, t+departure_delay*rate);
+
+                       list<Departure>::iterator i = collected_departures.begin();
+                       bool duplicate = false;
+                       for(; (i!=collected_departures.end() && !duplicate); ++i)
+                       {
+                               if(i->time>dep.time)
+                               {
+                                       duplicate = (i->time<dep.time+Time::min);
+                                       break;
+                               }
+                               else
+                                       duplicate = (i->time+Time::min>dep.time);
+                       }
+
+                       if(!duplicate)
+                               collected_departures.push_back(dep);
+               }
+
+       merge_departures(train, collected_departures);
+}
+
+void Departures::merge_departures(Train &train, const std::list<Departure> &collected_departures)
+{
+       list<Departure>::iterator i = departures.begin();
+       list<Departure>::const_iterator j = collected_departures.begin();
+       while(i!=departures.end() && j!=collected_departures.end())
+       {
+               if(i->time>j->time)
+               {
+                       list<Departure>::iterator k = departures.insert(i, *j);
+                       signal_departure_added.emit(*k);
+                       ++j;
+               }
+               else if(i->train==&train)
+               {
+                       if(i->time==j->time)
+                       {
+                               ++i;
+                               ++j;
+                       }
+                       else
+                       {
+                               signal_departure_removed.emit(*i);
+                               departures.erase(i++);
+                       }
+               }
+               else
+                       ++i;
+       }
+
+       for(; j!=collected_departures.end(); ++j)
+       {
+               departures.push_back(*j);
+               signal_departure_added.emit(departures.back());
+       }
+
+       for(; i!=departures.end(); )
+       {
+               if(i->train==&train)
+               {
+                       signal_departure_removed.emit(*i);
+                       departures.erase(i++);
+               }
+               else
+                       ++i;
+       }
+}
+
+Zone *Departures::get_attached_zone(const TrackChain &chain) const
+{
+       const TrackChain::TrackSet &tracks = chain.get_tracks();
+       for(vector<Zone *>::const_iterator i=zones.begin(); i!=zones.end(); ++i)
+       {
+               for(TrackChain::TrackSet::const_iterator j=tracks.begin(); j!=tracks.end(); ++j)
+                       if((*i)->has_track(**j))
+                               return *i;
+       }
+
+       return 0;
+}
+
+
+Departures::Departure::Departure(Zone &z, Train &t, const Time::TimeDelta &m):
+       zone(&z),
+       train(&t),
+       time(m)
+{ }
+
+} // namespace R2C2