From: Mikko Rasa Date: Sat, 8 Jun 2013 18:46:54 +0000 (+0300) Subject: Better algorithms for dealing with turnouts in a Route X-Git-Url: http://git.tdb.fi/?a=commitdiff_plain;h=e802ad7de31cc23bce2c0a3533a7ccd6635a30c1;p=r2c2.git Better algorithms for dealing with turnouts in a Route --- diff --git a/source/libr2c2/route.cpp b/source/libr2c2/route.cpp index ffb420a..c8f1ed3 100644 --- a/source/libr2c2/route.cpp +++ b/source/libr2c2/route.cpp @@ -151,58 +151,14 @@ void Route::set_temporary(bool t) temporary = t; } -void Route::set_turnout(unsigned addr, unsigned path) -{ - if(!addr) - throw invalid_argument("Route::set_turnout"); - int &state = get_item(turnouts, addr); - if(state>=0 && path!=static_cast(state)) - throw logic_error("route conflict"); - state = path; -} - void Route::update_turnouts() { set found; for(set::const_iterator i=tracks.begin(); i!=tracks.end(); ++i) - if(unsigned tid = (*i)->get_turnout_id()) + if((*i)->get_type().is_turnout()) { - found.insert(tid); - - const vector &endpoints = (*i)->get_type().get_endpoints(); - const vector &links = (*i)->get_links(); - - // Build a combined path mask from linked endpoints - unsigned mask = (*i)->get_type().get_paths(); - for(unsigned j=0; jget_turnout_id()) - { - const TrackType::Endpoint &ep = links[j]->get_type().get_endpoint(links[j]->get_link_slot(**i)); - int p = get_turnout(tid2); - if(p>=0 && !ep.has_path(p)) - { - // The linked track is a turnout and has a path which is incompatible with this endpoint - mask &= ~endpoints[j].paths; - continue; - } - } - mask &= endpoints[j].paths; - } - - if(mask && !(mask&(mask-1))) - { - // Exactly one possible choice, set the path accordingly - unsigned path = 0; - for(; (mask && !(mask&1)); mask>>=1, ++path) ; - turnouts[tid] = path; - } - else if(!turnouts.count(tid)) - // More than one possible choice, and no existing entry - set as undecided - turnouts[tid] = -1; + found.insert((*i)->get_turnout_id()); + update_turnout(**i); } // Remove any turnouts that do not exist in the route @@ -215,6 +171,43 @@ void Route::update_turnouts() } } +void Route::update_turnout(Track &track) +{ + // Build a combined path mask from linked endpoints + unsigned nls = track.get_n_link_slots(); + unsigned mask = track.get_type().get_paths(); + for(unsigned i=0; iget_type().is_turnout()) + { + const TrackType::Endpoint &link_ep = link->get_type().get_endpoint(link->get_link_slot(track)); + int p = get_turnout(link->get_turnout_id()); + if(p>=0 && !link_ep.has_path(p)) + // The linked track is a turnout and has a path which is incompatible with this endpoint + ep_mask = ~ep_mask; + } + + mask &= ep_mask; + } + + unsigned tid = track.get_turnout_id(); + if(mask && !(mask&(mask-1))) + { + // Exactly one possible choice, set the path accordingly + unsigned path = 0; + for(; (mask && !(mask&1)); mask>>=1, ++path) ; + turnouts[tid] = path; + } + else if(!turnouts.count(tid)) + // More than one possible choice, and no existing entry - set as undecided + turnouts[tid] = -1; +} + int Route::get_turnout(unsigned id) const { map::const_iterator i = turnouts.find(id); @@ -234,39 +227,30 @@ unsigned Route::get_path(Track &trk) const return trk.get_active_path(); } -void Route::add_track_chain(const TrackIter &start, const TurnoutMap &trnts) +void Route::add_turnout(Track &track, unsigned path) { - if(!start) - throw invalid_argument("Route::add_track_chain"); - - TrackIter iter = start; - while(iter) - { - if(iter->get_type().is_dead_end()) - break; - - if(has_track(*iter)) - break; - - int path = 0; - if(iter->get_turnout_id()) + TrackSet tracks_to_add; + tracks_to_add.insert(&track); + unsigned nls = track.get_n_link_slots(); + for(unsigned i=0; iget_turnout_id()); - if(i==trnts.end()) - break; - - path = i->second; + TrackIter iter = TrackIter(&track, i).flip(); + for(; (iter && !iter->get_type().is_turnout()); iter=iter.next()) + tracks_to_add.insert(&*iter); } - add_track(*iter); - - iter = iter.next(path); - } + add_tracks(tracks_to_add); } -void Route::on_track_added(Track &) +void Route::on_track_added(Track &track) { - update_turnouts(); + update_turnout(track); + unsigned nls = track.get_n_link_slots(); + for(unsigned i=0; i &st) const @@ -307,29 +291,25 @@ Route::Loader::Loader(Route &r): void Route::Loader::finish() { const set <racks = obj.layout.get_all(); + map turnout_tracks; for(set::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; - - const vector &eps = (*i)->get_type().get_endpoints(); - for(unsigned k=0; ksecond)) - { - Track *link = (*i)->get_link(k); - if(!obj.tracks.count(link)) - obj.add_track_chain(TrackIter(link, link->get_link_slot(**i)), turnouts); - if(!obj.tracks.count(*i)) - obj.add_track_chain(TrackIter(*i, k), turnouts); - break; - } + if((*i)->get_type().is_turnout()) + { + TurnoutMap::iterator j = turnouts.find((*i)->get_turnout_id()); + if(j!=turnouts.end()) + turnout_tracks[*i] = j->second; + } - break; + for(map::iterator i=turnout_tracks.begin(); i!=turnout_tracks.end(); ) + { + if(obj.check_validity(*i->first)==VALID) + { + obj.add_turnout(*i->first, i->second); + turnout_tracks.erase(i); + i = turnout_tracks.begin(); + } + else + ++i; } } diff --git a/source/libr2c2/route.h b/source/libr2c2/route.h index 9b440cb..3bd4a44 100644 --- a/source/libr2c2/route.h +++ b/source/libr2c2/route.h @@ -49,13 +49,15 @@ public: const std::string &get_name() const { return name; } void set_temporary(bool); bool is_temporary() const { return temporary; } - void set_turnout(unsigned, unsigned); void update_turnouts(); +private: + void update_turnout(Track &); +public: int get_turnout(unsigned) const; unsigned get_path(Track &) const; const std::map &get_turnouts() const { return turnouts; } - void add_track_chain(const TrackIter &, const TurnoutMap &); private: + void add_turnout(Track &, unsigned); virtual void on_track_added(Track &); public: