]> git.tdb.fi Git - r2c2.git/commitdiff
Generate IDs for new turnouts
authorMikko Rasa <tdb@tdb.fi>
Thu, 14 Oct 2010 19:25:50 +0000 (19:25 +0000)
committerMikko Rasa <tdb@tdb.fi>
Thu, 14 Oct 2010 19:25:50 +0000 (19:25 +0000)
Update routes when a turnout ID is changed
Properly support non-loop routes
Link tracks as they are loaded
Don't move tracks when linking if one of them is flexible
Move route rebuilding to the Route class

source/designer/designer.cpp
source/libmarklin/layout.cpp
source/libmarklin/layout.h
source/libmarklin/route.cpp
source/libmarklin/route.h
source/libmarklin/track.cpp
source/libmarklin/tracktype.cpp
source/libmarklin/tracktype.h

index c6d253e30b275b76d4a62d9f29228ae480ee1815..396cb074c98b6cd83deae38f4b9df443d4473c7f 100644 (file)
@@ -489,8 +489,11 @@ void Designer::update_track_icon(Track3D &track)
        }
        else if(unsigned tid = track.get_track().get_turnout_id())
        {
-               overlay->add_graphic(track, "turnout");
-               overlay->set_label(track, lexical_cast(tid));
+               if(tid<0x800)
+               {
+                       overlay->add_graphic(track, "turnout");
+                       overlay->set_label(track, lexical_cast(tid));
+               }
        }
 }
 
index 1448a1d76eef08085e76f4604c29fc2586b43e04..a495a21968b62ade01645c3e733939d101c1feea 100644 (file)
@@ -28,7 +28,8 @@ namespace Marklin {
 
 Layout::Layout(Catalogue &c, Driver *d):
        catalogue(c),
-       driver(d)
+       driver(d),
+       next_turnout_id(0x800)
 {
        if(driver)
                driver->signal_sensor.connect(sigc::mem_fun(this, &Layout::sensor_event));
@@ -72,6 +73,11 @@ void Layout::remove_track(Track &t)
        }
 }
 
+unsigned Layout::allocate_turnout_id()
+{
+       return next_turnout_id++;
+}
+
 void Layout::add_block(Block &b)
 {
        blocks.insert(&b);
@@ -157,6 +163,12 @@ Route &Layout::get_route(const string &name) const
        return *i->second;
 }
 
+void Layout::update_routes()
+{
+       for(map<string, Route *>::iterator i=routes.begin(); i!=routes.end(); ++i)
+               i->second->update_turnouts();
+}
+
 void Layout::remove_route(Route &r)
 {
        if(routes.erase(r.get_name()))
@@ -264,106 +276,6 @@ void Layout::save_trains(const string &fn)
        }
 }
 
-void Layout::check_links()
-{
-       for(set<Track *>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
-               (*i)->break_links();
-
-       list<Track *> flext;
-       for(set<Track *>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
-       {
-               if((*i)->get_flex())
-                       flext.push_back(*i);
-               else
-               {
-                       for(set<Track *>::iterator j=i; j!=tracks.end(); ++j)
-                               if(j!=i)
-                                       (*i)->snap_to(**j, true);
-               }
-       }
-
-       for(list<Track *>::iterator i=flext.begin(); i!=flext.end(); ++i)
-               for(set<Track *>::iterator j=tracks.begin(); j!=tracks.end(); ++j)
-                       if(*j!=*i)
-                               (*i)->snap_to(**j, true);
-}
-
-void Layout::check_routes()
-{
-       for(map<string, Route *>::iterator i=routes.begin(); i!=routes.end(); ++i)
-       {
-               if(i->second->is_temporary())
-                       continue;
-
-               /* We must copy the turnout map, since adding tracks to the route will
-               (temporarily) mess it up */
-               const map<unsigned, int> turnouts = i->second->get_turnouts();
-
-               // Find any turnout in the route
-               Track *track = 0;
-               unsigned trk_path = 0;
-               for(set<Track *>::const_iterator j=tracks.begin(); j!=tracks.end(); ++j)
-               {
-                       map<unsigned, int>::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<Endpoint> &eps = track->get_type().get_endpoints();
-               unsigned ep = 0;
-               for(unsigned j=0; j<eps.size(); ++j)
-                       if(eps[j].paths&(1<<trk_path))
-                       {
-                               ep = j;
-                               break;
-                       }
-
-               Track *start = 0;
-               while(1)
-               {
-                       // Traverse the track and get the next one
-                       if(track->get_type().get_endpoints().size()<2)
-                               break;
-                       unsigned out_ep = track->traverse(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().is_turnout())
-                       {
-                               // Select correct path across the turnout, or break if we hit an unknown turnout
-                               map<unsigned, int>::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;
-               }
-       }
-}
-
 void Layout::sensor_event(unsigned addr, bool state)
 {
        if(state)
@@ -391,10 +303,6 @@ Layout::Loader::Loader(Layout &l):
 
 void Layout::Loader::finish()
 {
-       if(new_tracks)
-               obj.check_links();
-       obj.check_routes();
-
        for(set<Track *>::iterator i=obj.tracks.begin(); i!=obj.tracks.end(); ++i)
                (*i)->check_slope();
 }
@@ -410,6 +318,9 @@ void Layout::Loader::track(unsigned art_nr)
        Track *trk = new Track(obj, obj.catalogue.get_track(art_nr));
        load_sub(*trk);
        new_tracks = true;
+       for(set<Track *>::iterator i=obj.tracks.begin(); i!=obj.tracks.end(); ++i)
+               if(*i!=trk)
+                       trk->snap_to(**i, true);
 }
 
 void Layout::Loader::train(unsigned art_nr, unsigned addr)
index 6683e2d7ddb8de5c91ac781781c9c9fdb1bc01d9..f820cb5dc73e6c6fc05166ab6816de11b7922c06 100644 (file)
@@ -62,6 +62,7 @@ private:
        std::map<unsigned, Train *> trains;
        std::set<Vehicle *> vehicles;
        Msp::Time::TimeStamp last_tick;
+       unsigned next_turnout_id;
 
 public:
        Layout(Catalogue &, Driver * = 0);
@@ -75,6 +76,7 @@ public:
        void add_track(Track &);
        const std::set<Track *> &get_tracks() const { return tracks; }
        void remove_track(Track &);
+       unsigned allocate_turnout_id();
 
        void add_block(Block &);
        Block &get_block(unsigned) const;
@@ -87,6 +89,7 @@ public:
        void add_route(Route &);
        const std::map<std::string, Route *> &get_routes() const { return routes; }
        Route &get_route(const std::string &) const;
+       void update_routes();
        void remove_route(Route &);
 
        void add_train(Train &);
@@ -103,8 +106,6 @@ public:
        void save(const std::string &);
        void save_trains(const std::string &);
 private:
-       void check_links();
-       void check_routes();
        void sensor_event(unsigned, bool);
 };
 
index 7ecd473694926ea306067f1993e03ad16b08a0cf..cdbcf1dc4c8cc778f4183277dae9c6b65616f572 100644 (file)
@@ -213,17 +213,44 @@ void Route::add_tracks(const set<const Track *> &trks)
        update_turnouts();
 }
 
-void Route::save(list<DataFile::Statement> &st) const
+void Route::add_track_chain(const Track &start, unsigned ep, const TurnoutMap &trnts)
 {
-       for(map<unsigned, int>::const_iterator i=turnouts.begin(); i!=turnouts.end(); ++i)
-               st.push_back((DataFile::Statement("turnout"), i->first, i->second));
+       const Track *track = &start;
+       while(1)
+       {
+               if(track->get_type().is_dead_end())
+                       break;
+
+               if(tracks.count(track))
+                       break;
+
+               int path = 0;
+               if(track->get_turnout_id())
+               {
+                       TurnoutMap::const_iterator i = trnts.find(track->get_turnout_id());
+                       if(i==trnts.end())
+                               break;
+
+                       path = i->second;
+               }
+
+               add_track(*track);
+
+               unsigned out_ep = track->traverse(ep, path);
+               Track *next = track->get_links()[out_ep];
+               if(!next)
+                       break;
+
+               ep = next->get_endpoint_by_link(*track);
+               track = next;
+       }
 }
 
 void Route::update_turnouts()
 {
        set<unsigned> found;
        for(set<const Track *>::const_iterator i=tracks.begin(); i!=tracks.end(); ++i)
-               if(unsigned tid=(*i)->get_turnout_id())
+               if(unsigned tid = (*i)->get_turnout_id())
                {
                        found.insert(tid);
 
@@ -237,7 +264,7 @@ void Route::update_turnouts()
                                if(!tracks.count(links[j]))
                                        continue;
 
-                               if(unsigned tid2=links[j]->get_turnout_id())
+                               if(unsigned tid2 = links[j]->get_turnout_id())
                                {
                                        const Endpoint &ep = links[j]->get_type().get_endpoints()[links[j]->get_endpoint_by_link(**i)];
                                        int p = get_turnout(tid2);
@@ -273,6 +300,12 @@ void Route::update_turnouts()
        }
 }
 
+void Route::save(list<DataFile::Statement> &st) const
+{
+       for(map<unsigned, int>::const_iterator i=turnouts.begin(); i!=turnouts.end(); ++i)
+               st.push_back((DataFile::Statement("turnout"), i->first, i->second));
+}
+
 unsigned Route::check_validity(const Track &trk) const
 {
        unsigned result = 4;
@@ -347,9 +380,37 @@ Route::Loader::Loader(Route &r):
        add("turnout", &Loader::turnout);
 }
 
+void Route::Loader::finish()
+{
+       const set<Track *> &ltracks = obj.layout.get_tracks();
+       for(set<Track *>::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<<j->second;
+               const vector<Endpoint> &eps = (*i)->get_type().get_endpoints();
+               for(unsigned k=0; k<eps.size(); ++k)
+                       if(eps[k].paths&path_mask)
+                       {
+                               Track *link = (*i)->get_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;
+                       }
+       }
+}
+
 void Route::Loader::turnout(unsigned id, unsigned path)
 {
-       obj.turnouts[id] = path;
+       turnouts[id] = path;
 }
 
 } // namespace Marklin
index 010bb873c8e0971ae0a8022677df26b001b04a7a..6b36f46ec3ed5a68fbad407aef800f2d76f64eb1 100644 (file)
@@ -22,11 +22,17 @@ class Track;
 class Route: public sigc::trackable
 {
 public:
+       typedef std::map<unsigned, int> TurnoutMap;
+
        class Loader: public Msp::DataFile::BasicLoader<Route>
        {
+       private:
+               TurnoutMap turnouts;
+
        public:
                Loader(Route &);
        private:
+               virtual void finish();
                void turnout(unsigned, unsigned);
        };
 
@@ -35,7 +41,7 @@ private:
        std::string name;
        bool temporary;
        std::set<const Track *> tracks;
-       std::map<unsigned, int> turnouts;
+       TurnoutMap turnouts;
 
 public:
        Route(Layout &, const std::string &);
@@ -44,14 +50,15 @@ public:
        const std::string &get_name() const { return name; }
        void set_temporary(bool);
        bool is_temporary() const { return temporary; }
+       void update_turnouts();
        int get_turnout(unsigned) const;
        const std::map<unsigned, int> &get_turnouts() const { return turnouts; }
        void add_track(const Track &);
        void add_tracks(const std::set<const Track *> &);
+       void add_track_chain(const Track &, unsigned, const TurnoutMap &);
        const std::set<const Track *> &get_tracks() const { return tracks; }
        void save(std::list<Msp::DataFile::Statement> &) const;
 private:
-       void update_turnouts();
        unsigned check_validity(const Track &) const;
        void track_removed(Track &);
 
index 05f9f2f717c1044b47446b73aeab0ac01f68b73b..74e51acab73fddb2246b750d23a3339b9e2dab24 100644 (file)
@@ -22,9 +22,9 @@ Track::Track(Layout &l, const TrackType &t):
        rot(0),
        slope(0),
        flex(false),
-       turnout_id(0),
+       turnout_id(type.is_turnout() ? layout.allocate_turnout_id() : 0),
        sensor_id(0),
-       links(t.get_endpoints().size()),
+       links(type.get_endpoints().size()),
        active_path(0)
 {
        layout.add_track(*this);
@@ -103,6 +103,7 @@ void Track::set_turnout_id(unsigned i)
 
        turnout_id = i;
        layout.create_blocks(*this);
+       layout.update_routes();
        if(layout.has_driver() && turnout_id)
        {
                layout.get_driver().add_turnout(turnout_id);
@@ -175,7 +176,7 @@ float Track::get_endpoint_direction(unsigned epi) const
 
 bool Track::snap_to(Track &other, bool link)
 {
-       float limit = (link && !flex) ? 1e-6 : 1e-4;
+       float limit = (link && !flex && !other.get_flex()) ? 1e-6 : 1e-4;
        const vector<Endpoint> &eps = type.get_endpoints();
        const vector<Endpoint> &other_eps = other.get_type().get_endpoints();
 
@@ -193,13 +194,16 @@ bool Track::snap_to(Track &other, bool link)
                        float dy = epp2.y-epp.y;
                        if(dx*dx+dy*dy<limit)
                        {
-                               set_rotation(other.rot+other_eps[j].dir-eps[i].dir+M_PI);
-                               Point p(epp2.x-(eps[i].pos.x*cos(rot)-eps[i].pos.y*sin(rot)),
-                                       epp2.y-(eps[i].pos.y*cos(rot)+eps[i].pos.x*sin(rot)),
-                                       epp2.z);
-                               if(eps.size()==2 && i==1)
-                                       p.z -= slope;
-                               set_position(p);
+                               if(!link || (!flex && !other.get_flex()))
+                               {
+                                       set_rotation(other.rot+other_eps[j].dir-eps[i].dir+M_PI);
+                                       Point p(epp2.x-(eps[i].pos.x*cos(rot)-eps[i].pos.y*sin(rot)),
+                                               epp2.y-(eps[i].pos.y*cos(rot)+eps[i].pos.x*sin(rot)),
+                                               epp2.z);
+                                       if(eps.size()==2 && i==1)
+                                               p.z -= slope;
+                                       set_position(p);
+                               }
 
                                if(link)
                                {
index d86977918655541b377fab7117f057289e931350..1a39877a94bbb649d86b193e133c4030aa61a1a1 100644 (file)
@@ -53,6 +53,11 @@ bool TrackType::is_turnout() const
        return endpoints.size()>2;
 }
 
+bool TrackType::is_dead_end() const
+{
+       return endpoints.size()<2;
+}
+
 TrackPoint TrackType::get_point(unsigned epi, unsigned path, float d) const
 {
        if(epi>=endpoints.size())
index 582f77ae25b1a506bbd49b28c6fec8cfea3f57e7..99989be664ae15e7ba3f14dd64be865b8da186e5 100644 (file)
@@ -44,6 +44,7 @@ public:
        unsigned get_paths() const;
        unsigned get_n_paths() const;
        bool is_turnout() const;
+       bool is_dead_end() const;
        bool is_double_address() const { return double_address; }
        const std::vector<TrackPart> &get_parts() const { return parts; }
        const std::vector<Endpoint> &get_endpoints() const { return endpoints; }