X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Flibr2c2%2Froute.cpp;h=5ee30e033161030fa31a8f558f50e7f4a3b9aaea;hb=f86223ef906cad5c492c95d069550f262f5b3dff;hp=ad6f81169e5a36221e05934ba5f4cb0e7d6439e3;hpb=2dce9f86c82b6ada591f2a2f0135edceb95756f3;p=r2c2.git diff --git a/source/libr2c2/route.cpp b/source/libr2c2/route.cpp index ad6f811..5ee30e0 100644 --- a/source/libr2c2/route.cpp +++ b/source/libr2c2/route.cpp @@ -1,12 +1,7 @@ -/* $Id$ - -This file is part of R²C² -Copyright © 2007-2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - #include -#include +#include +#include +#include #include "layout.h" #include "route.h" #include "track.h" @@ -88,9 +83,9 @@ list dijkstra(const TrackIter &from, const Pred &goal) break; } - unsigned paths = lowest.track.endpoint().paths; - for(unsigned i=0; paths>>i; ++i) - if(paths&(1<>i; ++i) + if(ep.has_path(i)) { TrackIter next = lowest.track.next(i); if(!next) @@ -134,22 +129,15 @@ Route *create_route(const TrackIter &from, const Pred &goal) namespace R2C2 { Route::Route(Layout &l): - layout(l), + TrackChain(l), temporary(false) { - layout.add_route(*this); - layout.signal_track_removed.connect(sigc::mem_fun(this, &Route::track_removed)); + layout.add(*this); } Route::~Route() { - layout.remove_route(*this); -} - -void Route::set_name(const string &n) -{ - name = n; - signal_name_changed.emit(name); + layout.remove(*this); } void Route::set_temporary(bool t) @@ -157,60 +145,14 @@ void Route::set_temporary(bool t) temporary = t; } -void Route::set_turnout(unsigned addr, unsigned path) -{ - if(!addr) - throw InvalidParameterValue("Invalid turnout address"); - map::iterator i = turnouts.find(addr); - if(i==turnouts.end()) - throw KeyError("Turnout is not in this route"); - if(i->second>=0 && path!=static_cast(i->second)) - throw InvalidState("Setting conflicts with route"); - i->second = 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_endpoint_by_link(**i)); - int p = get_turnout(tid2); - if(p>=0 && !(ep.paths&(1<>=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_address()); + update_turnout(**i); } // Remove any turnouts that do not exist in the route @@ -223,6 +165,46 @@ void Route::update_turnouts() } } +void Route::update_turnout(Track &track) +{ + if(!track.get_type().is_turnout()) + return; + + // 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_address()); + 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 taddr = track.get_turnout_address(); + if(mask && !(mask&(mask-1))) + { + // Exactly one possible choice, set the path accordingly + unsigned path = 0; + for(; (mask && !(mask&1)); mask>>=1, ++path) ; + turnouts[taddr] = path; + } + else if(!turnouts.count(taddr)) + // More than one possible choice, and no existing entry - set as undecided + turnouts[taddr] = -1; +} + int Route::get_turnout(unsigned id) const { map::const_iterator i = turnouts.find(id); @@ -233,91 +215,39 @@ int Route::get_turnout(unsigned id) const unsigned Route::get_path(Track &trk) const { - if(unsigned tid = trk.get_turnout_id()) + if(trk.get_type().is_turnout()) { - map::const_iterator i = turnouts.find(tid); - if(i!=turnouts.end()) + map::const_iterator i = turnouts.find(trk.get_turnout_address()); + if(i!=turnouts.end() && i->second>=0) return i->second; } return trk.get_active_path(); } -void Route::add_track(Track &trk) +void Route::add_turnout(Track &track, unsigned path) { - if(tracks.count(&trk)) - return; - - if(!tracks.empty()) - { - unsigned valid = check_validity(trk); - if(!(valid&1)) - throw Exception("Not linked to existing tracks"); - else if(!(valid&2)) - throw Exception("Branching routes not allowed"); - else if(!(valid&4)) - throw Exception("Route must be smooth"); - } - - tracks.insert(&trk); - update_turnouts(); -} - -void Route::add_tracks(const set &trks) -{ - set pending; - for(set::const_iterator i=trks.begin(); i!=trks.end(); ++i) - if(!tracks.count(*i)) - pending.insert(*i); - - while(!pending.empty()) - { - bool found = false; - for(set::const_iterator i=pending.begin(); i!=pending.end(); ++i) - if(tracks.empty() || check_validity(**i)==7) - { - tracks.insert(*i); - pending.erase(*i); - found = true; - break; - } - - if(!found) - throw Exception("Could not add all tracks to route"); - } - - update_turnouts(); -} - -void Route::add_track_chain(Track &start, unsigned ep, const TurnoutMap &trnts) -{ - TrackIter iter(&start, ep); - 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); } -bool Route::has_track(Track &t) const +void Route::on_track_added(Track &track) { - return tracks.count(&t); + update_turnout(track); + unsigned nls = track.get_n_link_slots(); + for(unsigned i=0; i &st) const @@ -327,72 +257,9 @@ void Route::save(list &st) const st.push_back((DataFile::Statement("turnout"), i->first, i->second)); } -unsigned Route::check_validity(Track &trk) const -{ - unsigned result = 4; - const vector &links = trk.get_links(); - for(vector::const_iterator i=links.begin(); i!=links.end(); ++i) - { - if(!*i) - continue; - if(!tracks.count(*i)) - continue; - - // Linked to an existing track - good - result |= 1; - - if(unsigned tid = (*i)->get_turnout_id()) - { - const TrackType::Endpoint &ep = (*i)->get_type().get_endpoint((*i)->get_endpoint_by_link(trk)); - int path = get_turnout(tid); - if(path>=0) - { - // Linking to a turnout with path set is only good if we're continuing that path - if(ep.paths&(1< &tlinks = (*i)->get_links(); - unsigned count = 0; - for(unsigned j=0; jget_turnout_id(); - if(tid2) - { - const TrackType::Endpoint &ep2 = tlinks[j]->get_type().get_endpoint(tlinks[j]->get_endpoint_by_link(**i)); - path = get_turnout(tid2); - // Ignore a linked turnout with some other path set - if(path>=0 && !(ep2.paths&(1<get_type().get_endpoint(j); - if(!(ep.paths&ep2.paths)) - // Impossible path through the turnout - not good - result &= 3; - } - - // Only good if at most one other track is linked to the turnout - if(count<=1) - result |= 2; - } - } - else - // Linked to something linear - good - result |= 2; - } - - return result; -} - -void Route::track_removed(Track &t) +DataFile::Statement Route::save_reference() const { - tracks.erase(&t); + return (DataFile::Statement("route"), name); } Route *Route::find(const TrackIter &from, Track &to) @@ -417,42 +284,42 @@ Route *Route::find(const TrackIter &from, const set &to) Route::Loader::Loader(Route &r): - DataFile::BasicLoader(r) + DataFile::ObjectLoader(r) { - add("name", &Route::name); + add("name", &Loader::name); add("turnout", &Loader::turnout); } void Route::Loader::finish() { - const set <racks = obj.layout.get_tracks(); + 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; - - unsigned path_mask = 1<second; - const vector &eps = (*i)->get_type().get_endpoints(); - for(unsigned k=0; kget_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; - } + if((*i)->get_type().is_turnout()) + { + TurnoutMap::iterator j = turnouts.find((*i)->get_turnout_address()); + 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; } } +void Route::Loader::name(const string &n) +{ + obj.name = n; +} + void Route::Loader::turnout(unsigned id, unsigned path) { turnouts[id] = path;