}
else if(unsigned tid = track.get_track().get_turnout_id())
{
- overlay->add_graphic(track, "turnout");
- overlay->set_label(track, lexical_cast(tid));
+ if(tid<0x800)
+ {
+ overlay->add_graphic(track, "turnout");
+ overlay->set_label(track, lexical_cast(tid));
+ }
}
}
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));
}
}
+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()))
}
}
-void Layout::check_links()
-{
- 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((*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)
- {
- if(i->second->is_temporary())
- continue;
-
- /* 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))
- {
- ep = j;
- break;
- }
-
- Track *start = 0;
- while(1)
- {
- // Traverse the track and get the next one
- if(track->get_type().get_endpoints().size()<2)
- break;
- 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::sensor_event(unsigned addr, bool state)
{
if(state)
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)
std::map<unsigned, Train *> trains;
std::set<Vehicle *> vehicles;
Msp::Time::TimeStamp last_tick;
+ unsigned next_turnout_id;
public:
Layout(Catalogue &, Driver * = 0);
void add_track(Track &);
const std::set<Track *> &get_tracks() const { return tracks; }
void remove_track(Track &);
+ unsigned allocate_turnout_id();
void add_block(Block &);
Block &get_block(unsigned) const;
void add_route(Route &);
const std::map<std::string, Route *> &get_routes() const { return routes; }
Route &get_route(const std::string &) const;
+ void update_routes();
void remove_route(Route &);
void add_train(Train &);
void save(const std::string &);
void save_trains(const std::string &);
private:
- void check_links();
- void check_routes();
void sensor_event(unsigned, bool);
};
update_turnouts();
}
-void Route::save(list<DataFile::Statement> &st) const
+void Route::add_track_chain(const Track &start, unsigned ep, const TurnoutMap &trnts)
{
- for(map<unsigned, int>::const_iterator i=turnouts.begin(); i!=turnouts.end(); ++i)
- st.push_back((DataFile::Statement("turnout"), i->first, i->second));
+ const Track *track = &start;
+ while(1)
+ {
+ if(track->get_type().is_dead_end())
+ break;
+
+ if(tracks.count(track))
+ break;
+
+ int path = 0;
+ if(track->get_turnout_id())
+ {
+ TurnoutMap::const_iterator i = trnts.find(track->get_turnout_id());
+ if(i==trnts.end())
+ break;
+
+ path = i->second;
+ }
+
+ add_track(*track);
+
+ unsigned out_ep = track->traverse(ep, path);
+ Track *next = track->get_links()[out_ep];
+ if(!next)
+ break;
+
+ ep = next->get_endpoint_by_link(*track);
+ track = next;
+ }
}
void Route::update_turnouts()
{
set<unsigned> found;
for(set<const Track *>::const_iterator i=tracks.begin(); i!=tracks.end(); ++i)
- if(unsigned tid=(*i)->get_turnout_id())
+ if(unsigned tid = (*i)->get_turnout_id())
{
found.insert(tid);
if(!tracks.count(links[j]))
continue;
- if(unsigned tid2=links[j]->get_turnout_id())
+ if(unsigned tid2 = links[j]->get_turnout_id())
{
const Endpoint &ep = links[j]->get_type().get_endpoints()[links[j]->get_endpoint_by_link(**i)];
int p = get_turnout(tid2);
}
}
+void Route::save(list<DataFile::Statement> &st) const
+{
+ for(map<unsigned, int>::const_iterator i=turnouts.begin(); i!=turnouts.end(); ++i)
+ st.push_back((DataFile::Statement("turnout"), i->first, i->second));
+}
+
unsigned Route::check_validity(const Track &trk) const
{
unsigned result = 4;
add("turnout", &Loader::turnout);
}
+void Route::Loader::finish()
+{
+ const set<Track *> <racks = obj.layout.get_tracks();
+ for(set<Track *>::const_iterator i=ltracks.begin(); i!=ltracks.end(); ++i)
+ {
+ unsigned tid = (*i)->get_turnout_id();
+ if(!tid)
+ continue;
+
+ TurnoutMap::iterator j = turnouts.find(tid);
+ if(j==turnouts.end())
+ continue;
+
+ unsigned path_mask = 1<<j->second;
+ const vector<Endpoint> &eps = (*i)->get_type().get_endpoints();
+ for(unsigned k=0; k<eps.size(); ++k)
+ if(eps[k].paths&path_mask)
+ {
+ Track *link = (*i)->get_link(k);
+ if(!obj.tracks.count(link))
+ obj.add_track_chain(*link, link->get_endpoint_by_link(**i), turnouts);
+ if(!obj.tracks.count(*i))
+ obj.add_track_chain(**i, k, turnouts);
+ break;
+ }
+ }
+}
+
void Route::Loader::turnout(unsigned id, unsigned path)
{
- obj.turnouts[id] = path;
+ turnouts[id] = path;
}
} // namespace Marklin
class Route: public sigc::trackable
{
public:
+ typedef std::map<unsigned, int> TurnoutMap;
+
class Loader: public Msp::DataFile::BasicLoader<Route>
{
+ private:
+ TurnoutMap turnouts;
+
public:
Loader(Route &);
private:
+ virtual void finish();
void turnout(unsigned, unsigned);
};
std::string name;
bool temporary;
std::set<const Track *> tracks;
- std::map<unsigned, int> turnouts;
+ TurnoutMap turnouts;
public:
Route(Layout &, const std::string &);
const std::string &get_name() const { return name; }
void set_temporary(bool);
bool is_temporary() const { return temporary; }
+ void update_turnouts();
int get_turnout(unsigned) const;
const std::map<unsigned, int> &get_turnouts() const { return turnouts; }
void add_track(const Track &);
void add_tracks(const std::set<const Track *> &);
+ void add_track_chain(const Track &, unsigned, const TurnoutMap &);
const std::set<const Track *> &get_tracks() const { return tracks; }
void save(std::list<Msp::DataFile::Statement> &) const;
private:
- void update_turnouts();
unsigned check_validity(const Track &) const;
void track_removed(Track &);
rot(0),
slope(0),
flex(false),
- turnout_id(0),
+ turnout_id(type.is_turnout() ? layout.allocate_turnout_id() : 0),
sensor_id(0),
- links(t.get_endpoints().size()),
+ links(type.get_endpoints().size()),
active_path(0)
{
layout.add_track(*this);
turnout_id = i;
layout.create_blocks(*this);
+ layout.update_routes();
if(layout.has_driver() && turnout_id)
{
layout.get_driver().add_turnout(turnout_id);
bool Track::snap_to(Track &other, bool link)
{
- float limit = (link && !flex) ? 1e-6 : 1e-4;
+ float limit = (link && !flex && !other.get_flex()) ? 1e-6 : 1e-4;
const vector<Endpoint> &eps = type.get_endpoints();
const vector<Endpoint> &other_eps = other.get_type().get_endpoints();
float dy = epp2.y-epp.y;
if(dx*dx+dy*dy<limit)
{
- set_rotation(other.rot+other_eps[j].dir-eps[i].dir+M_PI);
- Point p(epp2.x-(eps[i].pos.x*cos(rot)-eps[i].pos.y*sin(rot)),
- epp2.y-(eps[i].pos.y*cos(rot)+eps[i].pos.x*sin(rot)),
- epp2.z);
- if(eps.size()==2 && i==1)
- p.z -= slope;
- set_position(p);
+ if(!link || (!flex && !other.get_flex()))
+ {
+ set_rotation(other.rot+other_eps[j].dir-eps[i].dir+M_PI);
+ Point p(epp2.x-(eps[i].pos.x*cos(rot)-eps[i].pos.y*sin(rot)),
+ epp2.y-(eps[i].pos.y*cos(rot)+eps[i].pos.x*sin(rot)),
+ epp2.z);
+ if(eps.size()==2 && i==1)
+ p.z -= slope;
+ set_position(p);
+ }
if(link)
{
return endpoints.size()>2;
}
+bool TrackType::is_dead_end() const
+{
+ return endpoints.size()<2;
+}
+
TrackPoint TrackType::get_point(unsigned epi, unsigned path, float d) const
{
if(epi>=endpoints.size())
unsigned get_paths() const;
unsigned get_n_paths() const;
bool is_turnout() const;
+ bool is_dead_end() const;
bool is_double_address() const { return double_address; }
const std::vector<TrackPart> &get_parts() const { return parts; }
const std::vector<Endpoint> &get_endpoints() const { return endpoints; }