#include <msp/core/refptr.h>
#include <msp/datafile/parser.h>
#include <msp/datafile/writer.h>
+#include <msp/io/print.h>
#include <msp/time/utils.h>
#include "block.h"
#include "catalogue.h"
#include "driver.h"
#include "layout.h"
-#include "locotype.h"
#include "route.h"
#include "track.h"
#include "tracktype.h"
#include "train.h"
+#include "vehicletype.h"
using namespace std;
using namespace Msp;
Layout::Layout(Catalogue &c, Driver *d):
catalogue(c),
- driver(d)
-{ }
+ driver(d),
+ next_turnout_id(0x800)
+{
+ if(driver)
+ driver->signal_sensor.connect(sigc::mem_fun(this, &Layout::sensor_event));
+}
Layout::~Layout()
{
}
}
+unsigned Layout::allocate_turnout_id()
+{
+ return next_turnout_id++;
+}
+
void Layout::add_block(Block &b)
{
blocks.insert(&b);
return *i->second;
}
+void Layout::update_routes()
+{
+ for(map<string, Route *>::iterator i=routes.begin(); i!=routes.end(); ++i)
+ i->second->update_turnouts();
+}
+
void Layout::remove_route(Route &r)
{
if(routes.erase(r.get_name()))
signal_train_removed.emit(t);
}
+void Layout::add_vehicle(Vehicle &v)
+{
+ if(vehicles.insert(&v).second)
+ signal_vehicle_added.emit(v);
+}
+
+void Layout::remove_vehicle(Vehicle &v)
+{
+ if(vehicles.erase(&v))
+ signal_vehicle_removed.emit(v);
+}
+
void Layout::tick()
{
if(driver)
i->second->tick(t, dt);
}
+void Layout::emergency(const string &msg)
+{
+ if(driver)
+ driver->halt(true);
+ IO::print("Emergency: %s\n", msg);
+ signal_emergency.emit(msg);
+}
+
void Layout::save(const string &fn)
{
IO::BufferedFile out(fn, IO::M_WRITE);
for(map<string, Route *>::iterator i=routes.begin(); i!=routes.end(); ++i)
{
+ if(i->second->is_temporary())
+ continue;
+
DataFile::Statement st("route");
st.append(i->first);
i->second->save(st.sub);
}
}
-void Layout::check_links()
+void Layout::sensor_event(unsigned addr, bool state)
{
- for(set<Track *>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
- (*i)->break_links();
-
- list<Track *> flext;
- for(set<Track *>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
+ if(state)
{
- if((*i)->get_flex())
- flext.push_back(*i);
- else
- {
- for(set<Track *>::iterator j=i; j!=tracks.end(); ++j)
- if(j!=i)
- (*i)->snap_to(**j, true);
- }
- }
-
- for(list<Track *>::iterator i=flext.begin(); i!=flext.end(); ++i)
- for(set<Track *>::iterator j=tracks.begin(); j!=tracks.end(); ++j)
- if(*j!=*i)
- (*i)->snap_to(**j, true);
-}
-
-void Layout::check_routes()
-{
- for(map<string, Route *>::iterator i=routes.begin(); i!=routes.end(); ++i)
- {
- /* We must copy the turnout map, since adding tracks to the route will
- (temporarily) mess it up */
- const map<unsigned, int> turnouts = i->second->get_turnouts();
-
- // Find any turnout in the route
- Track *track = 0;
- unsigned trk_path = 0;
- for(set<Track *>::const_iterator j=tracks.begin(); j!=tracks.end(); ++j)
- {
- map<unsigned, int>::const_iterator k = turnouts.find((*j)->get_turnout_id());
- if(k!=turnouts.end())
- {
- track = *j;
- trk_path = k->second;
- break;
- }
- }
-
- if(!track)
- continue;
-
- // Find an applicable endpoint
- const vector<Endpoint> &eps = track->get_type().get_endpoints();
- unsigned ep = 0;
- for(unsigned j=0; j<eps.size(); ++j)
- if(eps[j].paths&(1<<trk_path))
+ for(set<Block *>::iterator i=blocks.begin(); i!=blocks.end(); ++i)
+ if((*i)->get_sensor_id()==addr)
{
- ep = j;
+ if(!(*i)->get_train())
+ emergency(format("Unreserved sensor %d triggered", addr));
break;
}
-
- Track *start = 0;
- while(1)
- {
- // Traverse the track and get the next one
- unsigned out_ep = track->traverse(ep, trk_path);
- Track *next = track->get_links()[out_ep];
- if(!next || next == start)
- break;
-
- ep = next->get_endpoint_by_link(*track);
- if(next->get_type().is_turnout())
- {
- // Select correct path across the turnout, or break if we hit an unknown turnout
- map<unsigned, int>::const_iterator j = turnouts.find(next->get_turnout_id());
- if(j==turnouts.end())
- break;
- trk_path = j->second;
- }
- else
- {
- trk_path = 0;
-
- /* Start adding tracks when we find the first non-turnout. This
- prevents the occurrence of ambiguities while adding the tracks */
- if(!start)
- start = next;
- }
-
- if(start)
- i->second->add_track(*next);
-
- track = next;
- }
}
}
void Layout::Loader::finish()
{
- if(new_tracks)
- obj.check_links();
- obj.check_routes();
-
for(set<Track *>::iterator i=obj.tracks.begin(); i!=obj.tracks.end(); ++i)
(*i)->check_slope();
}
Track *trk = new Track(obj, obj.catalogue.get_track(art_nr));
load_sub(*trk);
new_tracks = true;
+ for(set<Track *>::iterator i=obj.tracks.begin(); i!=obj.tracks.end(); ++i)
+ if(*i!=trk)
+ trk->snap_to(**i, true);
}
void Layout::Loader::train(unsigned art_nr, unsigned addr)
{
- Train *trn = new Train(obj, obj.catalogue.get_locomotive(art_nr), addr);
+ Train *trn = new Train(obj, obj.catalogue.get_vehicle(art_nr), addr);
load_sub(*trn);
}