+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)