X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;ds=sidebyside;f=source%2Flibmarklin%2Flayout.cpp;h=4e6620b2e1bcbb6704446efef85aabf5015c3b90;hb=02c9a9779954d993cb73fe5f7a72b0847e87f633;hp=a197b35af596002a4ed7a202a24a77ea54537c10;hpb=1d735b80482317fd930eb47ca255ab9f1f120a7d;p=r2c2.git diff --git a/source/libmarklin/layout.cpp b/source/libmarklin/layout.cpp index a197b35..4e6620b 100644 --- a/source/libmarklin/layout.cpp +++ b/source/libmarklin/layout.cpp @@ -1,6 +1,13 @@ -#include +/* $Id$ + +This file is part of the MSP Märklin suite +Copyright © 2006-2009 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + #include #include +#include #include "catalogue.h" #include "layout.h" #include "tracktype.h" @@ -10,7 +17,7 @@ using namespace Msp; namespace Marklin { -Layout::Layout(Catalogue &c): +Layout::Layout(const Catalogue &c): catalogue(c) { } @@ -18,6 +25,8 @@ Layout::~Layout() { for(set::iterator i=tracks.begin(); i!=tracks.end(); ++i) delete *i; + for(map::iterator i=routes.begin(); i!=routes.end(); ++i) + delete i->second; } void Layout::add_track(Track &t) @@ -28,89 +37,184 @@ void Layout::add_track(Track &t) void Layout::remove_track(Track &t) { - if(tracks.count(&t)) - { - tracks.erase(&t); + if(tracks.erase(&t)) signal_track_removed.emit(t); - } } -void Layout::check_links() +void Layout::add_route(Route &r) { - for(set::iterator i=tracks.begin(); i!=tracks.end(); ++i) - (*i)->break_links(); - - for(set::iterator i=tracks.begin(); i!=tracks.end(); ++i) - for(set::iterator j=i; j!=tracks.end(); ++j) - if(j!=i) - (*i)->snap_to(**j, true); + if(routes.count(r.get_name())) + throw KeyError("Duplicate route name"); + routes[r.get_name()] = &r; + signal_route_added.emit(r); } -void Layout::load(const string &fn) +Route &Layout::get_route(const string &name) const { - IO::File in(fn); - IO::Buffered inb(in); - - filename=fn; - DataFile::Parser parser(inb, fn); - Loader loader(*this); - loader.load(parser); - - check_links(); - - for(set::iterator i=tracks.begin(); i!=tracks.end(); ++i) - (*i)->check_slope(); + map::const_iterator i = routes.find(name); + if(i==routes.end()) + throw KeyError("Unknown route", name); + return *i->second; } -int Layout::save(const string &fn) +void Layout::remove_route(Route &r) { - ofstream out(fn.c_str()); - if(!out) return -1; + if(routes.erase(r.get_name())) + signal_route_removed.emit(r); +} - filename=fn; +void Layout::save(const string &fn) +{ + IO::BufferedFile out(fn, IO::M_WRITE); + DataFile::Writer writer(out); if(!base.empty()) - out<<"base \""<::iterator i=tracks.begin(); i!=tracks.end(); ++i) { - out<<"track "<<(*i)->get_type().get_article_number()<<"\n{\n"; - const Point &p=(*i)->get_position(); - out<<"\tposition "<get_rotation()<<";\n"; - out<<"\tslope "<<(*i)->get_slope()<<";\n"; + DataFile::Statement st("track"); + st.append((*i)->get_type().get_article_number()); + (*i)->save(st.sub); + writer.write(st); + } - unsigned id=(*i)->get_turnout_id(); - if(id) - out<<"\tturnout_id "<::iterator i=routes.begin(); i!=routes.end(); ++i) + { + DataFile::Statement st("route"); + st.append(i->first); + i->second->save(st.sub); + writer.write(st); + } +} - id=(*i)->get_sensor_id(); - if(id) - out<<"\tsensor_id "<::iterator i=tracks.begin(); i!=tracks.end(); ++i) + (*i)->break_links(); + list flext; + for(set::iterator i=tracks.begin(); i!=tracks.end(); ++i) + { if((*i)->get_flex()) - out<<"\tflex true;\n"; - - out<<"};\n"; + flext.push_back(*i); + else + { + for(set::iterator j=i; j!=tracks.end(); ++j) + if(j!=i) + (*i)->snap_to(**j, true); + } } - return 0; + for(list::iterator i=flext.begin(); i!=flext.end(); ++i) + for(set::iterator j=tracks.begin(); j!=tracks.end(); ++j) + if(*j!=*i) + (*i)->snap_to(**j, true); +} + +void Layout::check_routes() +{ + for(map::iterator i=routes.begin(); i!=routes.end(); ++i) + { + /* We must copy the turnout map, since adding tracks to the route will + (temporarily) mess it up */ + const map turnouts = i->second->get_turnouts(); + + // Find any turnout in the route + Track *track = 0; + unsigned trk_path = 0; + for(set::const_iterator j=tracks.begin(); j!=tracks.end(); ++j) + { + map::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 &eps = track->get_type().get_endpoints(); + unsigned ep = 0; + for(unsigned j=0; jtraverse(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().get_n_paths()>1) + { + // Select correct path across the turnout, or break if we hit an unknown turnout + map::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; + } + } } Layout::Loader::Loader(Layout &l): - layout(l) + DataFile::BasicLoader(l) { add("base", &Layout::base); + add("route", &Loader::route); add("track", &Loader::track); } +void Layout::Loader::finish() +{ + obj.check_links(); + obj.check_routes(); + + for(set::iterator i=obj.tracks.begin(); i!=obj.tracks.end(); ++i) + (*i)->check_slope(); +} + +void Layout::Loader::route(const string &n) +{ + RefPtr rte = new Route(obj, n); + load_sub(*rte); + obj.add_route(*rte.release()); +} + void Layout::Loader::track(unsigned art_nr) { - TrackType &type=layout.catalogue.get_track(art_nr); + TrackType &type = obj.catalogue.get_track(art_nr); - RefPtr trk=new Track(type); + RefPtr trk = new Track(type); load_sub(*trk); - layout.add_track(*trk.release()); + obj.add_track(*trk.release()); } } // namespace Marklin