X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Flibmarklin%2Froute.cpp;fp=source%2Flibmarklin%2Froute.cpp;h=0000000000000000000000000000000000000000;hb=1ff06c5bc46a677fa389ef86c6b26664368f1653;hp=79886d28c371c793ed223909ef343b79edc0b726;hpb=9b05c573a38639827697fe393d55b7c76f5bde45;p=r2c2.git diff --git a/source/libmarklin/route.cpp b/source/libmarklin/route.cpp deleted file mode 100644 index 79886d2..0000000 --- a/source/libmarklin/route.cpp +++ /dev/null @@ -1,455 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2007-2010 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#include -#include -#include "layout.h" -#include "route.h" -#include "track.h" -#include "trackiter.h" -#include "tracktype.h" - -using namespace std; -using namespace Msp; - -namespace { - -using namespace Marklin; - -typedef std::pair Key; - -struct Node -{ - TrackIter track; - Node *prev; - float dist; - - Node(): - prev(0), dist(0) - { } - - Node(const TrackIter &t): - track(t), prev(0), dist(0) - { } - - Node(const TrackIter &t, Node &r, float d): - track(t), prev(&r), dist(prev->dist+d) - { } - - bool operator<(const Node &other) const - { return dist>other.dist; } -}; - -struct TrackMatch -{ - Track &track; - - TrackMatch(Track &t): track(t) { } - - bool operator()(Track &t) const { return &t==&track; } -}; - -struct TrackInSet -{ - const set &tracks; - - TrackInSet(const set &t): tracks(t) { } - - bool operator()(Track &t) const { return tracks.count(&t); } -}; - -template -list dijkstra(const TrackIter &from, const Pred &goal) -{ - map track_nodes; - priority_queue nodes; - Node *final = 0; - - nodes.push(from); - - while(!nodes.empty()) - { - Node lowest = nodes.top(); - nodes.pop(); - - Key key(lowest.track.track(), lowest.track.entry()); - if(track_nodes.count(key)) - continue; - - Node &ref = track_nodes[key] = lowest; - if(goal(*lowest.track)) - { - final = &ref; - break; - } - - unsigned paths = lowest.track.endpoint().paths; - for(unsigned i=0; paths>>i; ++i) - if(paths&(1<get_type().get_path_length(i))); - } - } - - list result; - for(Node *node=final; node; node=node->prev) - result.push_front(&*node->track); - - return result; -} - -template -Route *create_route(const TrackIter &from, const Pred &goal) -{ - list tracks = dijkstra(from, goal); - - if(tracks.empty()) - return 0; - - Route *route = new Route(from->get_layout()); - for(list::iterator i=tracks.begin(); i!=tracks.end(); ++i) - route->add_track(**i); - - route->set_name("Pathfinder"); - route->set_temporary(true); - - return route; -} - -} - - -namespace Marklin { - -Route::Route(Layout &l): - layout(l), - temporary(false) -{ - layout.add_route(*this); - layout.signal_track_removed.connect(sigc::mem_fun(this, &Route::track_removed)); -} - -Route::~Route() -{ - layout.remove_route(*this); -} - -void Route::set_name(const string &n) -{ - name = n; - signal_name_changed.emit(name); -} - -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()) - { - 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; - } - - // Remove any turnouts that do not exist in the route - for(map::iterator i=turnouts.begin(); i!=turnouts.end();) - { - if(!found.count(i->first)) - turnouts.erase(i++); - else - ++i; - } -} - -int Route::get_turnout(unsigned id) const -{ - map::const_iterator i = turnouts.find(id); - if(i!=turnouts.end()) - return i->second; - return -1; -} - -unsigned Route::get_path(Track &trk) const -{ - if(unsigned tid = trk.get_turnout_id()) - { - map::const_iterator i = turnouts.find(tid); - if(i!=turnouts.end()) - return i->second; - } - return trk.get_active_path(); -} - -void Route::add_track(Track &trk) -{ - 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()) - { - TurnoutMap::const_iterator i = trnts.find(iter->get_turnout_id()); - if(i==trnts.end()) - break; - - path = i->second; - } - - add_track(*iter); - - iter = iter.next(path); - } -} - -bool Route::has_track(Track &t) const -{ - return tracks.count(&t); -} - -void Route::save(list &st) const -{ - st.push_back((DataFile::Statement("name"), name)); - for(map::const_iterator i=turnouts.begin(); i!=turnouts.end(); ++i) - 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) -{ - tracks.erase(&t); -} - -Route *Route::find(const TrackIter &from, Track &to) -{ - return create_route(from, TrackMatch(to)); -} - -Route *Route::find(const TrackIter &from, const Route &to) -{ - return create_route(from, TrackInSet(to.get_tracks())); -} - -Route *Route::find(const TrackIter &from, const set &to) -{ - return create_route(from, TrackInSet(to)); -} - - -Route::Loader::Loader(Route &r): - DataFile::BasicLoader(r) -{ - add("name", &Route::name); - add("turnout", &Loader::turnout); -} - -void Route::Loader::finish() -{ - const set <racks = obj.layout.get_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; - } - - break; - } -} - -void Route::Loader::turnout(unsigned id, unsigned path) -{ - turnouts[id] = path; -} - -} // namespace Marklin