X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Flibr2c2%2Froute.cpp;h=80c61088eda68223be46299bac6621b289291d35;hb=54392d65e2053d1eacb4cfcc435f1013993f2973;hp=61117f5e5f851ae75501d9872724137d9ca60ce0;hpb=d15ac13f2e170f155b4bbd124df48400c339b644;p=r2c2.git diff --git a/source/libr2c2/route.cpp b/source/libr2c2/route.cpp index 61117f5..80c6108 100644 --- a/source/libr2c2/route.cpp +++ b/source/libr2c2/route.cpp @@ -1,5 +1,7 @@ #include -#include +#include +#include +#include #include "layout.h" #include "route.h" #include "track.h" @@ -81,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) @@ -126,6 +128,20 @@ Route *create_route(const TrackIter &from, const Pred &goal) namespace R2C2 { +string bad_route::get_message(RouteValidityMask valid) +{ + const char *reasons[3]; + unsigned i = 0; + if(!(valid&1)) + reasons[i++] = "unlinked"; + if(!(valid&2)) + reasons[i++] = "branching"; + if(!(valid&4)) + reasons[i++] = "not smooth"; + return join(reasons, reasons+i, ", "); +} + + Route::Route(Layout &l): layout(l), temporary(false) @@ -153,13 +169,11 @@ void Route::set_temporary(bool 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; + 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() @@ -182,9 +196,9 @@ void Route::update_turnouts() if(unsigned tid2 = links[j]->get_turnout_id()) { - const TrackType::Endpoint &ep = links[j]->get_type().get_endpoint(links[j]->get_endpoint_by_link(**i)); + 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.paths&(1<=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; @@ -242,13 +256,9 @@ void Route::add_track(Track &trk) 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"); + RouteValidityMask valid = check_validity(trk); + if(valid!=ROUTE_VALID) + throw bad_route(valid); } tracks.insert(&trk); @@ -262,28 +272,37 @@ void Route::add_tracks(const set &trks) if(!tracks.count(*i)) pending.insert(*i); + if(tracks.empty()) + { + set::iterator i = pending.begin(); + tracks.insert(*i); + pending.erase(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) + RouteValidityMask valid = ROUTE_INVALID; + for(set::iterator i=pending.begin(); i!=pending.end(); ++i) + if((valid=check_validity(**i))==ROUTE_VALID) { tracks.insert(*i); - pending.erase(*i); - found = true; + pending.erase(i); break; } - if(!found) - throw Exception("Could not add all tracks to route"); + if(valid!=ROUTE_VALID) + throw bad_route(valid); } update_turnouts(); } -void Route::add_track_chain(Track &start, unsigned ep, const TurnoutMap &trnts) +void Route::add_track_chain(const TrackIter &start, const TurnoutMap &trnts) { - TrackIter iter(&start, ep); + if(!start) + throw invalid_argument("Route::add_track_chain"); + + TrackIter iter = start; while(iter) { if(iter->get_type().is_dead_end()) @@ -320,9 +339,9 @@ void Route::save(list &st) const st.push_back((DataFile::Statement("turnout"), i->first, i->second)); } -unsigned Route::check_validity(Track &trk) const +RouteValidityMask Route::check_validity(Track &trk) const { - unsigned result = 4; + unsigned result = ROUTE_SMOOTH; const vector &links = trk.get_links(); for(vector::const_iterator i=links.begin(); i!=links.end(); ++i) { @@ -332,17 +351,17 @@ unsigned Route::check_validity(Track &trk) const continue; // Linked to an existing track - good - result |= 1; + result |= ROUTE_LINKED; if(unsigned tid = (*i)->get_turnout_id()) { - const TrackType::Endpoint &ep = (*i)->get_type().get_endpoint((*i)->get_endpoint_by_link(trk)); + const TrackType::Endpoint &ep = (*i)->get_type().get_endpoint((*i)->get_link_slot(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<get_turnout_id(); if(tid2) { - const TrackType::Endpoint &ep2 = tlinks[j]->get_type().get_endpoint(tlinks[j]->get_endpoint_by_link(**i)); + const TrackType::Endpoint &ep2 = tlinks[j]->get_type().get_endpoint(tlinks[j]->get_link_slot(**i)); path = get_turnout(tid2); // Ignore a linked turnout with some other path set - if(path>=0 && !(ep2.paths&(1<=0 && !ep2.has_path(path)) continue; } ++count; const TrackType::Endpoint &ep2 = (*i)->get_type().get_endpoint(j); - if(!(ep.paths&ep2.paths)) + if(!ep.has_common_paths(ep2)) // Impossible path through the turnout - not good - result &= 3; + result &= ~ROUTE_SMOOTH; } // Only good if at most one other track is linked to the turnout if(count<=1) - result |= 2; + result |= ROUTE_LINEAR; } } else // Linked to something linear - good - result |= 2; + result |= ROUTE_LINEAR; } - return result; + return static_cast(result); } void Route::track_removed(Track &t) @@ -410,7 +429,7 @@ 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("turnout", &Loader::turnout); @@ -429,16 +448,15 @@ void Route::Loader::finish() if(j==turnouts.end()) continue; - unsigned path_mask = 1<second; 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(*link, link->get_endpoint_by_link(**i), turnouts); + obj.add_track_chain(TrackIter(link, link->get_link_slot(**i)), turnouts); if(!obj.tracks.count(*i)) - obj.add_track_chain(**i, k, turnouts); + obj.add_track_chain(TrackIter(*i, k), turnouts); break; }