]> git.tdb.fi Git - r2c2.git/commitdiff
Add TrackIter and BlockIter classes
authorMikko Rasa <tdb@tdb.fi>
Mon, 25 Oct 2010 13:30:36 +0000 (13:30 +0000)
committerMikko Rasa <tdb@tdb.fi>
Mon, 25 Oct 2010 13:30:36 +0000 (13:30 +0000)
Remove the traverse functions in favor of the iterators

13 files changed:
source/engineer/trainpanel.cpp
source/libmarklin/block.cpp
source/libmarklin/block.h
source/libmarklin/blockiter.cpp [new file with mode: 0644]
source/libmarklin/blockiter.h [new file with mode: 0644]
source/libmarklin/route.cpp
source/libmarklin/track.cpp
source/libmarklin/track.h
source/libmarklin/trackiter.cpp [new file with mode: 0644]
source/libmarklin/trackiter.h [new file with mode: 0644]
source/libmarklin/train.cpp
source/libmarklin/train.h
source/libmarklin/vehicle.cpp

index a0dbbeef3890e345b773344f78c4c8d87ce6d8bd..96aa00df6de1816a3cbea78cb50d22570e965d28 100644 (file)
@@ -8,6 +8,7 @@ Distributed under the GPL
 #include <cmath>
 #include <msp/strings/formatter.h>
 #include "libmarklin/timetable.h"
+#include "libmarklin/trackiter.h"
 #include "libmarklin/vehicletype.h"
 #include "engineer.h"
 #include "routeselect.h"
@@ -263,13 +264,14 @@ void TrainPanel::place(Track *track, unsigned ep)
        pick_conn.disconnect();
 
        Block &block = track->get_block();
+       TrackIter iter(track, ep);
 
-       while(1)
+       while(block.has_track(*iter))
        {
                const vector<Block::Endpoint> &eps = block.get_endpoints();
                bool ok = false;
                for(unsigned i=0; (!ok && i<eps.size()); ++i)
-                       if(eps[i].track==track && eps[i].track_ep==ep)
+                       if(eps[i].track==iter.track() && eps[i].track_ep==iter.entry())
                        {
                                train.place(block, i);
                                ok = true;
@@ -277,14 +279,8 @@ void TrainPanel::place(Track *track, unsigned ep)
 
                if(ok)
                        break;
-               else
-               {
-                       Track *next = track->get_links()[ep];
-                       ep = next->traverse(next->get_endpoint_by_link(*track), 0);
-                       track = next;
-                       if(!block.has_track(*track))
-                               break;
-               }
+
+               iter = iter.flip().reverse();
        }
 }
 
index ec07947d7e1cbffa500f05b29661ba7178b99fa8..952fe50d56adc538ad6f4e8cab526cb815485a33 100644 (file)
@@ -9,6 +9,7 @@ Distributed under the GPL
 #include "block.h"
 #include "layout.h"
 #include "route.h"
+#include "trackiter.h"
 #include "tracktype.h"
 
 using namespace std;
@@ -93,45 +94,28 @@ int Block::get_endpoint_by_link(Block &other) const
        return -1;
 }
 
-unsigned Block::traverse(unsigned epi, float *len) const
+float Block::get_path_length(unsigned entry, const Route *route) const
 {
-       return traverse(epi, 0, len);
-}
-
-unsigned Block::traverse(unsigned epi, const Route *route, float *len) const
-{
-       if(epi>=endpoints.size())
+       if(entry>=endpoints.size())
                throw InvalidParameterValue("Endpoint index out of range");
 
-       const Endpoint &ep = endpoints[epi];
-       Track *track = ep.track;
-       unsigned track_ep = ep.track_ep;
+       TrackIter t_iter(endpoints[entry].track, endpoints[entry].track_ep);
 
-       if(len)
-               *len = 0;
-
-       while(1)
+       float result = 0;
+       while(t_iter && has_track(*t_iter))
        {
-               int cur_path = -1;
-               if(track->get_turnout_id() && route)
-                       cur_path = route->get_turnout(track->get_turnout_id());
-               if(cur_path==-1)
-                       cur_path = track->get_active_path();
-
-               if(len)
-                       *len += track->get_type().get_path_length(cur_path);
-
-               unsigned other_ep = track->traverse(track_ep, cur_path);
-               for(unsigned i=0; i<endpoints.size(); ++i)
-                       if(endpoints[i].track==track && endpoints[i].track_ep==static_cast<unsigned>(other_ep))
-                               return i;
-
-               Track *next = track->get_link(other_ep);
-               if(!tracks.count(next))
-                       throw LogicError("Block traversal strayed out of the block");
-               track_ep = next->get_endpoint_by_link(*track);
-               track = next;
+               int path = -1;
+               if(t_iter->get_turnout_id() && route)
+                       path = route->get_turnout(t_iter->get_turnout_id());
+               if(path==-1)
+                       path = t_iter->get_active_path();
+
+               result += t_iter->get_type().get_path_length(path);
+
+               t_iter = t_iter.next(path);
        }
+
+       return result;
 }
 
 void Block::check_link(Block &other)
index 23a48c0ffbc40344ee3c98a04c5e6833a3173613..cf5f3e784986f91ccc9010129a4d64213fb03bce 100644 (file)
@@ -51,8 +51,7 @@ public:
        bool has_track(Track &) const;
        const std::vector<Endpoint> &get_endpoints() const { return endpoints; }
        int get_endpoint_by_link(Block &) const;
-       unsigned traverse(unsigned, float * =0) const;
-       unsigned traverse(unsigned, const Route *, float * =0) const;
+       float get_path_length(unsigned, const Route * = 0) const;
        void check_link(Block &);
        void break_link(Block &);
        Block *get_link(unsigned) const;
diff --git a/source/libmarklin/blockiter.cpp b/source/libmarklin/blockiter.cpp
new file mode 100644 (file)
index 0000000..7618e4b
--- /dev/null
@@ -0,0 +1,122 @@
+/* $Id$
+
+This file is part of the MSP Märklin suite
+Copyright © 2010  Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#include <msp/core/except.h>
+#include "block.h"
+#include "blockiter.h"
+#include "route.h"
+#include "trackiter.h"
+
+using namespace std;
+using namespace Msp;
+
+namespace Marklin {
+
+BlockIter::BlockIter():
+       _block(0),
+       _entry(0)
+{ }
+
+BlockIter::BlockIter(Block *b, unsigned e):
+       _block(b),
+       _entry(b ? e : 0)
+{
+       if(_block && _entry>_block->get_endpoints().size())
+               throw InvalidParameterValue("Endpoint index not valid for block");
+}
+
+TrackIter BlockIter::track_iter() const
+{
+       if(!_block)
+               return TrackIter();
+
+       const Block::Endpoint &ep = _block->get_endpoints()[_entry];
+       return TrackIter(ep.track, ep.track_ep);
+}
+
+int BlockIter::get_exit(const Route *route) const
+{
+       const vector<Block::Endpoint> &eps = _block->get_endpoints();
+       TrackIter t_iter = track_iter();
+
+       while(t_iter)
+       {
+               if(!_block->has_track(*t_iter))
+                       throw LogicError("Block traversal strayed out of the block");
+
+               int path = -1;
+               if(t_iter->get_turnout_id() && route)
+                       path = route->get_turnout(t_iter->get_turnout_id());
+               if(path==-1)
+                       path = t_iter->get_active_path();
+
+               TrackIter t_exit = t_iter.reverse(path);
+
+               for(unsigned i=0; i<eps.size(); ++i)
+                       if(eps[i].track==t_exit.track() && eps[i].track_ep==t_exit.entry())
+                               return i;
+
+               t_iter = t_iter.next(path);
+       }
+
+       return -1;
+}
+
+BlockIter BlockIter::next(const Route *route) const
+{
+       if(!_block)
+               return BlockIter();
+
+       int exit = get_exit(route);
+       if(exit<0)
+               return BlockIter();
+
+       BlockIter result;
+       result._block = _block->get_link(exit);
+       result._entry = (result._block ? result._block->get_endpoint_by_link(*_block) : 0);
+
+       return result;
+}
+
+BlockIter BlockIter::reverse(const Route *route) const
+{
+       if(!_block)
+               return BlockIter();
+
+       int exit = get_exit(route);
+       if(exit<0)
+               return BlockIter();
+
+       return BlockIter(_block, exit);
+}
+
+BlockIter BlockIter::flip() const
+{
+       if(!_block)
+               return BlockIter();
+
+       BlockIter result;
+       result._block = _block->get_link(_entry);
+       result._entry = (result._block ? result._block->get_endpoint_by_link(*_block) : 0);
+
+       return result;
+}
+
+Block &BlockIter::operator*() const
+{
+       if(!_block)
+               throw InvalidState("BlockIter is null");
+
+       return *_block;
+}
+
+bool BlockIter::operator==(const BlockIter &other) const
+{
+       return _block==other._block && _entry==other._entry;
+}
+
+} // namespace Marklin
diff --git a/source/libmarklin/blockiter.h b/source/libmarklin/blockiter.h
new file mode 100644 (file)
index 0000000..2b8256f
--- /dev/null
@@ -0,0 +1,50 @@
+/* $Id$
+
+This file is part of the MSP Märklin suite
+Copyright © 2010  Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#ifndef LIBMARKLIN_BLOCKITER_H_
+#define LIBMARKLIN_BLOCKITER_H_
+
+namespace Marklin {
+
+class Block;
+class Route;
+class TrackIter;
+
+/**
+An iterator for traversing blocks.
+*/
+class BlockIter
+{
+private:
+       Block *_block;
+       unsigned _entry;
+
+public:
+       BlockIter();
+       BlockIter(Block *, unsigned);
+
+       Block *block() const { return _block; }
+       unsigned entry() const { return _entry; }
+       TrackIter track_iter() const;
+
+private:
+       int get_exit(const Route *) const;
+public:
+       BlockIter next(const Route * = 0) const;
+       BlockIter reverse(const Route * = 0) const;
+       BlockIter flip() const;
+
+       Block &operator*() const;
+       Block *operator->() const { return _block; }
+       bool operator==(const BlockIter &) const;
+       bool operator!=(const BlockIter &other) const { return !(*this==other); }
+       operator bool() const { return _block!=0; }
+};
+
+} // namespace Marklin
+
+#endif
index d4fcf800d9c30d71af8f7318e70a98b9f58bb7be..6dc7ae51e13350efe01269c06c199fde829675f8 100644 (file)
@@ -10,6 +10,7 @@ Distributed under the GPL
 #include "layout.h"
 #include "route.h"
 #include "track.h"
+#include "trackiter.h"
 #include "tracktype.h"
 
 using namespace std;
@@ -285,34 +286,28 @@ void Route::add_tracks(const set<Track *> &trks)
 
 void Route::add_track_chain(Track &start, unsigned ep, const TurnoutMap &trnts)
 {
-       Track *track = &start;
-       while(1)
+       TrackIter iter(&start, ep);
+       while(iter)
        {
-               if(track->get_type().is_dead_end())
+               if(iter->get_type().is_dead_end())
                        break;
 
-               if(tracks.count(track))
+               if(has_track(*iter))
                        break;
 
                int path = 0;
-               if(track->get_turnout_id())
+               if(iter->get_turnout_id())
                {
-                       TurnoutMap::const_iterator i = trnts.find(track->get_turnout_id());
+                       TurnoutMap::const_iterator i = trnts.find(iter->get_turnout_id());
                        if(i==trnts.end())
                                break;
 
                        path = i->second;
                }
 
-               add_track(*track);
+               add_track(*iter);
 
-               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;
+               iter = iter.next(path);
        }
 }
 
@@ -433,6 +428,8 @@ void Route::Loader::finish()
                                        obj.add_track_chain(**i, k, turnouts);
                                break;
                        }
+
+               break;
        }
 }
 
index 5f1ca438644eea5d094a09dcf61e019fe954f5f2..6ec3c3bf7cefc78041f3ddb357acdfb1b3fa203a 100644 (file)
@@ -293,37 +293,6 @@ Track *Track::get_link(unsigned i) const
        return links[i];
 }
 
-unsigned Track::traverse(unsigned i, unsigned path) const
-{
-       const vector<Endpoint> &eps = type.get_endpoints();
-       if(i>=eps.size())
-               throw InvalidParameterValue("Endpoint index out of range");
-
-       const Endpoint &ep = eps[i];
-       
-       if(ep.paths&(1<<path))
-       {
-               // Find the other endpoint for this path
-               for(unsigned j=0; j<eps.size(); ++j)
-                       if((eps[j].paths&(1<<path)) && j!=i)
-                               return j;
-       }
-       else
-       {
-               // Find an endpoint that's connected to this one and has the requested path
-               for(unsigned j=0; j<eps.size(); ++j)
-                       if((eps[j].paths&(1<<path)) && (eps[j].paths&ep.paths))
-                               return j;
-       }
-
-       throw Exception("Track endpoint did not have a counterpart");
-}
-
-unsigned Track::traverse(unsigned i) const
-{
-       return traverse(i, active_path);
-}
-
 TrackPoint Track::get_point(unsigned epi, unsigned path, float d) const
 {
        TrackPoint p = type.get_point(epi, path, d);
index f3d89815b72cb2a0a9338d583f02c2f4806396cf..eaf8de217c8c267bf7e2d831da8002aab4a5c878 100644 (file)
@@ -83,8 +83,6 @@ public:
        void break_links();
        const std::vector<Track *> &get_links() const { return links; }
        Track *get_link(unsigned) const;
-       unsigned traverse(unsigned, unsigned) const;
-       unsigned traverse(unsigned) const;
        TrackPoint get_point(unsigned, unsigned, float) const;
        TrackPoint get_point(unsigned, float) const;
 
diff --git a/source/libmarklin/trackiter.cpp b/source/libmarklin/trackiter.cpp
new file mode 100644 (file)
index 0000000..e8b327b
--- /dev/null
@@ -0,0 +1,112 @@
+/* $Id$
+
+This file is part of the MSP Märklin suite
+Copyright © 2010  Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#include <msp/core/except.h>
+#include "track.h"
+#include "trackiter.h"
+#include "tracktype.h"
+
+using namespace std;
+using namespace Msp;
+
+namespace Marklin {
+
+TrackIter::TrackIter():
+       _track(0),
+       _entry(0)
+{ }
+
+TrackIter::TrackIter(Track *t, unsigned e):
+       _track(t),
+       _entry(t ? e : 0)
+{
+       if(_track && _entry>_track->get_type().get_endpoints().size())
+               throw InvalidParameterValue("Endpoint index not valid for track");
+}
+
+int TrackIter::get_exit(unsigned path) const
+{
+       const vector<Endpoint> &eps = _track->get_type().get_endpoints();
+       
+       // Find an endpoint that's connected to the entry and has the requested path
+       for(unsigned i=0; i<eps.size(); ++i)
+               if(i!=_entry && (eps[i].paths&(1<<path)) && (eps[i].paths&eps[_entry].paths))
+                       return i;
+
+       return -1;
+}
+
+TrackIter TrackIter::next() const
+{
+       if(!_track)
+               return TrackIter();
+
+       return next(_track->get_active_path());
+}
+
+TrackIter TrackIter::next(unsigned path) const
+{
+       if(!_track)
+               return TrackIter();
+
+       int exit = get_exit(path);
+       if(exit<0)
+               return TrackIter();
+
+       TrackIter result;
+       result._track = _track->get_link(exit);
+       result._entry = (result._track ? result._track->get_endpoint_by_link(*_track) : 0);
+
+       return result;
+}
+
+TrackIter TrackIter::reverse() const
+{
+       if(!_track)
+               return TrackIter();
+
+       return reverse(_track->get_active_path());
+}
+
+TrackIter TrackIter::reverse(unsigned path) const
+{
+       if(!_track)
+               return TrackIter();
+
+       int exit = get_exit(path);
+       if(exit<0)
+               return TrackIter();
+
+       return TrackIter(_track, exit);
+}
+
+TrackIter TrackIter::flip() const
+{
+       if(!_track)
+               return TrackIter();
+
+       TrackIter result;
+       result._track = _track->get_link(_entry);
+       result._entry = (result._track ? result._track->get_endpoint_by_link(*_track) : 0);
+
+       return result;
+}
+
+Track &TrackIter::operator*() const
+{
+       if(!_track)
+               throw InvalidState("TrackIter is null");
+
+       return *_track;
+}
+
+bool TrackIter::operator==(const TrackIter &other) const
+{
+       return _track==other._track && _entry==other._entry;
+}
+
+} // namespace Marklin
diff --git a/source/libmarklin/trackiter.h b/source/libmarklin/trackiter.h
new file mode 100644 (file)
index 0000000..c91a768
--- /dev/null
@@ -0,0 +1,51 @@
+/* $Id$
+
+This file is part of the MSP Märklin suite
+Copyright © 2010  Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#ifndef LIBMARKLIN_TRACKITER_H_
+#define LIBMARKLIN_TRACKITER_H_
+
+#include <set>
+#include <msp/core/refptr.h>
+
+namespace Marklin {
+
+class Track;
+
+/**
+An iterator for traversing tracks.
+*/
+class TrackIter
+{
+private:
+       Track *_track;
+       unsigned _entry;
+
+public:
+       TrackIter();
+       TrackIter(Track *, unsigned);
+
+       Track *track() const { return _track; }
+       unsigned entry() const { return _entry; }
+
+private:
+       int get_exit(unsigned) const;
+public:
+       TrackIter next() const;
+       TrackIter next(unsigned) const;
+       TrackIter reverse() const;
+       TrackIter reverse(unsigned) const;
+       TrackIter flip() const;
+
+       Track &operator*() const;
+       Track *operator->() const { return _track; }
+       bool operator==(const TrackIter &) const;
+       operator bool() const { return _track!=0; }
+};
+
+} // namespace Marklin
+
+#endif
index 5bc50d85ff23ee5011535e34e5e6142f6b08fccc..cdb8e67d169297925a627c4b7556338316c0d9b6 100644 (file)
@@ -16,6 +16,7 @@ Distributed under the GPL
 #include "route.h"
 #include "simplecontroller.h"
 #include "timetable.h"
+#include "trackiter.h"
 #include "tracktype.h"
 #include "train.h"
 #include "vehicle.h"
@@ -214,18 +215,15 @@ void Train::set_route(const Route *r)
 
        if(r && !cur_blocks.empty())
        {
-               BlockRef &first = cur_blocks.front();
-               BlockRef &last = (rsv_blocks.empty() ? cur_blocks.back() : rsv_blocks.back());
-               BlockRef next = last.next();
-               const Block::Endpoint &first_ep = first.block->get_endpoints()[first.entry];
-               const Block::Endpoint &next_ep = next.block->get_endpoints()[next.entry];
-               if(!r->has_track(*next_ep.track))
+               TrackIter first = cur_blocks.front().track_iter();
+               TrackIter next = (rsv_blocks.empty() ? cur_blocks : rsv_blocks).back().next().track_iter();
+               if(!r->has_track(*next))
                {
-                       Route *lead = Route::find(*next_ep.track, next_ep.track_ep, *r);
+                       Route *lead = Route::find(*next, next.entry(), *r);
                        create_lead_route(lead, lead);
                        routes.push_front(lead);
                }
-               else if(!r->has_track(*first_ep.track))
+               else if(!r->has_track(*first))
                        routes.push_front(create_lead_route(0, r));
        }
 
@@ -236,8 +234,8 @@ void Train::set_route(const Route *r)
 
 void Train::go_to(Track &to)
 {
-       for(list<BlockRef>::const_iterator i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
-               if(i->block->has_track(to))
+       for(BlockList::const_iterator i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
+               if((*i)->has_track(to))
                {
                        signal_arrived.emit();
                        set_route(0);
@@ -246,11 +244,9 @@ void Train::go_to(Track &to)
 
        free_noncritical_blocks();
 
-       BlockRef &last = (rsv_blocks.empty() ? cur_blocks.back() : rsv_blocks.back());
-       BlockRef next = last.next();
-       const Block::Endpoint &ep = next.block->get_endpoints()[next.entry];
+       TrackIter next = (rsv_blocks.empty() ? cur_blocks : rsv_blocks).back().next().track_iter();
 
-       Route *route = Route::find(*ep.track, ep.track_ep, to);
+       Route *route = Route::find(*next, next.entry(), to);
        create_lead_route(route, route);
        set_route(route);
 }
@@ -265,18 +261,15 @@ bool Train::divert(Track &from)
        int path = -1;
        unsigned from_ep = 0;
        list<RouteRef>::iterator route = routes.begin();
-       Block *block = cur_blocks.back().block;
-       unsigned entry = cur_blocks.back().entry;
+       BlockIter block = cur_blocks.back();
        set<const Track *> visited;
 
        // Follow our routes to find out where we're entering the turnout
        while(1)
        {
-               Block *link = block->get_link(block->traverse(entry, route->route));
-               entry = link->get_endpoint_by_link(*block);
-               block = link;
+               block = block.next(route->route);
 
-               const Block::Endpoint &entry_ep = block->get_endpoints()[entry];
+               const Block::Endpoint &entry_ep = block->get_endpoints()[block.entry()];
 
                if(visited.count(entry_ep.track))
                        return false;
@@ -309,7 +302,7 @@ bool Train::divert(Track &from)
                        break;
                }
 
-       Track *track = from.get_link(from.traverse(from_ep, path));
+       TrackIter track = TrackIter(&from, from_ep).next(path);
        if(!track)
                return false;
 
@@ -342,22 +335,17 @@ bool Train::divert(Track &from)
        list<RouteRef>::iterator end = routes.end();
        while(1)
        {
-               path = 0;
-               if(track->get_turnout_id())
-                       path = diversion->get_turnout(track->get_turnout_id());
-               Track *next = track->get_link(track->traverse(ep, path));
-
                for(list<RouteRef>::iterator i=route; (end==routes.end() && i!=routes.end()); ++i)
-                       if(i->route->has_track(*next))
+                       if(i->route->has_track(*track))
                                end = i;
 
                if(end!=routes.end())
                        break;
-               else if(!diversion->has_track(*next))
+               else if(!diversion->has_track(*track))
                        throw Exception("Pathfinder returned a bad route");
 
-               ep = next->get_endpoint_by_link(*track);
-               track = next;
+               unsigned tid = track->get_turnout_id();
+               track = track.next(tid ? diversion->get_turnout(tid) : 0);
        }
 
        if(route==end)
@@ -397,14 +385,11 @@ void Train::place(Block &block, unsigned entry)
                return;
        }
 
-       cur_blocks.push_back(BlockRef(&block, entry));
+       cur_blocks.push_back(BlockIter(&block, entry));
        if(reverse)
        {
-               unsigned exit = block.traverse(entry);
-               const Block::Endpoint &bep = block.get_endpoints()[exit];
-               Track *track = bep.track->get_link(bep.track_ep);
-               unsigned ep = track->get_endpoint_by_link(*bep.track);
-               vehicles.front()->place(*track, ep, 0, Vehicle::FRONT_BUFFER);
+               TrackIter track = BlockIter(&block, entry).reverse().track_iter();
+               vehicles.front()->place(*track, track.entry(), 0, Vehicle::FRONT_BUFFER);
        }
        else
        {
@@ -437,16 +422,16 @@ bool Train::free_block(Block &block)
                return false;
 
        unsigned nsens = 0;
-       for(list<BlockRef>::iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
+       for(BlockList::iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
        {
-               if(i->block==&block)
+               if(i->block()==&block)
                {
                        if(nsens<1)
                                return false;
                        release_blocks(rsv_blocks, i, rsv_blocks.end());
                        return true;
                }
-               else if(i->block->get_sensor_id())
+               else if((*i)->get_sensor_id())
                        ++nsens;
        }
 
@@ -469,10 +454,10 @@ void Train::free_noncritical_blocks()
 
        Vehicle &veh = *(reverse ? vehicles.back() : vehicles.front());
 
-       Track *track = veh.get_track();
-       list<BlockRef>::iterator block = cur_blocks.begin();
+       TrackIter track(veh.get_track(), veh.get_entry());
+       BlockList::iterator block = cur_blocks.begin();
        bool in_rsv = false;
-       while(block!=rsv_blocks.end() && !block->block->has_track(*track))
+       while(block!=rsv_blocks.end() && !(*block)->has_track(*track))
        {
                ++block;
                if(block==cur_blocks.end())
@@ -482,10 +467,9 @@ void Train::free_noncritical_blocks()
                }
        }
 
-       unsigned entry = veh.get_entry();
        float dist = veh.get_offset();
        if(reverse)
-               entry = track->traverse(entry);
+               track.reverse();
        else
                dist = track->get_type().get_path_length(track->get_active_path())-dist;
        dist -= veh.get_type().get_length()/2;
@@ -493,11 +477,9 @@ void Train::free_noncritical_blocks()
        bool nsens = 0;
        while(1)
        {
-               Track *next = track->get_link(track->traverse(entry));
-               entry = next->get_endpoint_by_link(*track);
-               track = next;
+               track = track.next();
 
-               if(!block->block->has_track(*track))
+               if(!(*block)->has_track(*track))
                {
                        ++block;
                        if(block==cur_blocks.end())
@@ -514,7 +496,7 @@ void Train::free_noncritical_blocks()
                                return;
                        }
 
-                       if(in_rsv && block->block->get_sensor_id())
+                       if(in_rsv && (*block)->get_sensor_id())
                                ++nsens;
                }
 
@@ -524,12 +506,12 @@ void Train::free_noncritical_blocks()
 
 int Train::get_entry_to_block(Block &block) const
 {
-       for(list<BlockRef>::const_iterator i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
-               if(i->block==&block)
-                       return i->entry;
-       for(list<BlockRef>::const_iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
-               if(i->block==&block)
-                       return i->entry;
+       for(BlockList::const_iterator i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
+               if(i->block()==&block)
+                       return i->entry();
+       for(BlockList::const_iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
+               if(i->block()==&block)
+                       return i->entry();
        return -1;
 }
 
@@ -587,8 +569,8 @@ void Train::tick(const Time::TimeStamp &t, const Time::TimeDelta &dt)
                Track *track = vehicle.get_track();
 
                bool ok = false;
-               for(list<BlockRef>::const_iterator i=cur_blocks.begin(); (!ok && i!=cur_blocks.end()); ++i)
-                       ok = i->block->has_track(*track);
+               for(BlockList::const_iterator i=cur_blocks.begin(); (!ok && i!=cur_blocks.end()); ++i)
+                       ok = (*i)->has_track(*track);
 
                float d = get_real_speed(current_speed)*(dt/Time::sec);
                if(ok)
@@ -613,13 +595,13 @@ void Train::tick(const Time::TimeStamp &t, const Time::TimeDelta &dt)
                set_route(0);
        }
 
-       if(!cur_blocks.empty() && !cur_blocks.front().block->get_sensor_id())
+       if(!cur_blocks.empty() && !cur_blocks.front()->get_sensor_id())
        {
-               float dist = get_reserved_distance_until(cur_blocks.front().block, true);
+               float dist = get_reserved_distance_until(&*cur_blocks.front(), true);
 
                if(dist>10*layout.get_catalogue().get_scale())
                {
-                       cur_blocks.front().block->reserve(0);
+                       cur_blocks.front()->reserve(0);
                        cur_blocks.pop_front();
                }
        }
@@ -641,15 +623,15 @@ void Train::save(list<DataFile::Statement> &st) const
 
        if(!cur_blocks.empty())
        {
-               list<BlockRef> blocks = cur_blocks;
+               BlockList blocks = cur_blocks;
                if(reverse)
                        reverse_blocks(blocks);
 
-               Block *prev = blocks.front().block->get_endpoints()[blocks.front().entry].link;
+               BlockIter prev = blocks.front().flip();
                st.push_back((DataFile::Statement("block_hint"), prev->get_id()));
 
-               for(list<BlockRef>::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
-                       st.push_back((DataFile::Statement("block"), i->block->get_id()));
+               for(BlockList::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
+                       st.push_back((DataFile::Statement("block"), (*i)->get_id()));
        }
 
        if(!routes.empty())
@@ -703,12 +685,12 @@ void Train::sensor_event(unsigned addr, bool state)
        if(state)
        {
                // Find the first sensor block from our reserved blocks that isn't this sensor
-               list<BlockRef>::iterator i;
+               BlockList::iterator i;
                unsigned result = 0;
                for(i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
-                       if(i->block->get_sensor_id())
+                       if((*i)->get_sensor_id())
                        {
-                               if(i->block->get_sensor_id()!=addr)
+                               if((*i)->get_sensor_id()!=addr)
                                {
                                        if(result==0)
                                                result = 2;
@@ -737,23 +719,20 @@ void Train::sensor_event(unsigned addr, bool state)
                        }
 
                        travel_dist = 0;
-                       float block_len;
-                       for(list<BlockRef>::iterator j=rsv_blocks.begin(); j!=i; ++j)
+                       for(BlockList::iterator j=rsv_blocks.begin(); j!=i; ++j)
                        {
-                               j->block->traverse(j->entry, &block_len);
-                               travel_dist += block_len;
+                               travel_dist += (*j)->get_path_length(j->entry());
 
-                               if(j->block->get_sensor_id()==addr && !advancing)
+                               if((*j)->get_sensor_id()==addr && !advancing)
                                {
-                                       const Block::Endpoint &bep = j->block->get_endpoints()[j->entry];
+                                       TrackIter track = j->track_iter();
                                        if(reverse)
                                        {
-                                               Track *track = bep.track->get_link(bep.track_ep);
-                                               unsigned ep = track->get_endpoint_by_link(*bep.track);
-                                               vehicles.back()->place(*track, ep, 0, Vehicle::BACK_AXLE);
+                                               track = track.flip();
+                                               vehicles.back()->place(*track, track.entry(), 0, Vehicle::BACK_AXLE);
                                        }
                                        else
-                                               vehicles.front()->place(*bep.track, bep.track_ep, 0, Vehicle::FRONT_AXLE);
+                                               vehicles.front()->place(*track, track.entry(), 0, Vehicle::FRONT_AXLE);
                                }
                        }
                        last_entry_time = Time::now();
@@ -765,8 +744,8 @@ void Train::sensor_event(unsigned addr, bool state)
                        if(routes.size()>1)
                        {
                                const set<Track *> &rtracks = (++routes.begin())->route->get_tracks();
-                               for(list<BlockRef>::iterator j=rsv_blocks.begin(); j!=i; ++j)
-                                       if(rtracks.count(j->block->get_endpoints()[j->entry].track))
+                               for(BlockList::iterator j=rsv_blocks.begin(); j!=i; ++j)
+                                       if(rtracks.count((*j)->get_endpoints()[j->entry()].track))
                                        {
                                                routes.pop_front();
                                                // XXX Exceptions?
@@ -790,14 +769,14 @@ void Train::sensor_event(unsigned addr, bool state)
                const Vehicle &veh = *(reverse ? vehicles.front() : vehicles.back());
 
                // Find the first sensor in our current blocks that's still active
-               list<BlockRef>::iterator end = cur_blocks.begin();
-               for(list<BlockRef>::iterator i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
+               BlockList::iterator end = cur_blocks.begin();
+               for(BlockList::iterator i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
                {
-                       if(i->block->has_track(*veh.get_track()))
+                       if((*i)->has_track(*veh.get_track()))
                                break;
-                       if(i->block->get_sensor_id())
+                       if((*i)->get_sensor_id())
                        {
-                               if(layout.get_driver().get_sensor(i->block->get_sensor_id()))
+                               if(layout.get_driver().get_sensor((*i)->get_sensor_id()))
                                        break;
                                else
                                {
@@ -846,12 +825,12 @@ unsigned Train::reserve_more()
        if(!active)
                return 0;
 
-       BlockRef *start = 0;
+       BlockIter start;
        if(!rsv_blocks.empty())
-               start = &rsv_blocks.back();
+               start = rsv_blocks.back();
        else if(!cur_blocks.empty())
-               start = &cur_blocks.back();
-       if(!start)
+               start = cur_blocks.back();
+       else
                return 0;
 
        pending_block = 0;
@@ -859,60 +838,46 @@ unsigned Train::reserve_more()
        // See how many sensor blocks and how much track we already have
        unsigned nsens = 0;
        float dist = 0;
-       for(list<BlockRef>::const_iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
+       for(BlockList::const_iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
        {
-               if(i->block->get_sensor_id())
+               if((*i)->get_sensor_id())
                        ++nsens;
                if(nsens>0)
-               {
-                       float length = 0;
-                       i->block->traverse(i->entry, &length);
-                       dist += length;
-               }
+                       dist += (*i)->get_path_length(i->entry());
        }
        
        if(end_of_route)
                return nsens;
 
        list<RouteRef>::iterator cur_route = routes.begin();
-       advance_route(cur_route, *start->block->get_endpoints()[start->entry].track);
+       advance_route(cur_route, *start.track_iter());
 
        float approach_margin = 50*layout.get_catalogue().get_scale();
        float min_dist = controller->get_braking_distance()*1.3+approach_margin*2;
 
-       BlockRef *last = start;
-       BlockRef *good = start;
+       BlockIter block = start;
+       BlockIter good = start;
        Track *divert_track = 0;
        bool try_divert = false;
        unsigned good_sens = nsens;
        float good_dist = dist;
        Train *blocking_train = 0;
-       std::list<BlockRef> contested_blocks;
+       BlockList contested_blocks;
 
        SetFlag setf(reserving);
 
        while(good_sens<3 || good_dist<min_dist || !contested_blocks.empty())
        {
-               // Traverse to the next block
-               float length = 0;
-               Block *link = 0;
-               {
-                       const Route *route = (cur_route!=routes.end() ? cur_route->route : 0);
-                       unsigned exit = last->block->traverse(last->entry, route, &length);
-                       link = last->block->get_link(exit);
-               }
-               if(!link)
+               BlockIter last = block;
+               block = block.next(cur_route!=routes.end() ? cur_route->route : 0);
+               if(!block)
                        break;
 
-               int entry = link->get_endpoint_by_link(*last->block);
-               if(entry<0)
-                       throw LogicError("Block links are inconsistent!");
-
-               const Block::Endpoint &entry_ep = link->get_endpoints()[entry];
+               TrackIter track = block.track_iter();
 
                if(cur_route!=routes.end())
                {
-                       if(!advance_route(cur_route, *entry_ep.track))
+                       if(!advance_route(cur_route, *track))
                        {
                                // Keep the blocks if we arrived at the end of the route
                                if(!blocking_train)
@@ -925,10 +890,10 @@ unsigned Train::reserve_more()
                                break;
                        }
                }
-               else if(!routes.empty() && routes.front().route->has_track(*entry_ep.track))
+               else if(!routes.empty() && routes.front().route->has_track(*track))
                        cur_route = routes.begin();
 
-               if(link->get_endpoints().size()<2)
+               if(block->get_endpoints().size()<2)
                {
                        if(!blocking_train)
                        {
@@ -941,14 +906,14 @@ unsigned Train::reserve_more()
 
                if(blocking_train)
                {
-                       if(link->get_train()!=blocking_train)
+                       if(block->get_train()!=blocking_train)
                        {
-                               if(blocking_train->free_block(*contested_blocks.back().block))
+                               if(blocking_train->free_block(*contested_blocks.back()))
                                {
                                        // Roll back and start actually reserving the blocks
-                                       last = &rsv_blocks.back();
+                                       block = rsv_blocks.back();
                                        cur_route = routes.begin();
-                                       advance_route(cur_route, *last->block->get_endpoints()[last->entry].track);
+                                       advance_route(cur_route, *block.track_iter().track());
                                        if(blocking_train->get_priority()==priority)
                                                blocking_train->yield_to(*this);
                                        blocking_train = 0;
@@ -957,34 +922,35 @@ unsigned Train::reserve_more()
                                else
                                {
                                        yield_to(*blocking_train);
-                                       pending_block = contested_blocks.front().block;
+                                       pending_block = contested_blocks.front().block();
                                        try_divert = divert_track;
                                        break;
                                }
                        }
                        else
                        {
-                               contested_blocks.push_back(BlockRef(link, entry));
-                               last = &contested_blocks.back();
+                               contested_blocks.push_back(block);
                                continue;
                        }
                }
 
-               bool reserved = link->reserve(this);
+               bool reserved = block->reserve(this);
                if(!reserved)
                {
                        /* We've found another train.  If it wants to exit the block from the
                        same endpoint we're trying to enter from or the other way around,
                        treat it as coming towards us.  Otherwise treat it as going in the
                        same direction. */
-                       Train *other_train = link->get_train();
-                       int other_entry = other_train->get_entry_to_block(*link);
+                       Train *other_train = block->get_train();
+                       int other_entry = other_train->get_entry_to_block(*block);
                        if(other_entry<0)
                                throw LogicError("Block reservation inconsistency");
 
-                       bool entry_conflict = (static_cast<unsigned>(entry)==link->traverse(other_entry));
-                       bool exit_conflict = (link->traverse(entry)==static_cast<unsigned>(other_entry));
-                       if(!entry_conflict && !last->block->get_turnout_id())
+                       unsigned exit = block.reverse().entry();
+                       unsigned other_exit = BlockIter(block.block(), other_entry).reverse().entry();
+                       bool entry_conflict = (block.entry()==other_exit);
+                       bool exit_conflict = (exit==static_cast<unsigned>(other_entry));
+                       if(!entry_conflict && !last->get_turnout_id())
                        {
                                /* The other train is not coming to the blocks we're holding, so we
                                can keep them. */
@@ -999,8 +965,8 @@ unsigned Train::reserve_more()
                        {
                                /* Ask a lesser priority train going to the same direction to free
                                the block for us */
-                               if(other_train->free_block(*link))
-                                       reserved = link->reserve(this);
+                               if(other_train->free_block(*block))
+                                       reserved = block->reserve(this);
                        }
                        else if(other_train!=yielding_to && (other_prio<priority || (other_prio==priority && entry_conflict)))
                        {
@@ -1008,8 +974,7 @@ unsigned Train::reserve_more()
                                enough blocks to get clear of it to avoid a potential deadlock */
                                blocking_train = other_train;
                                contested_blocks.clear();
-                               contested_blocks.push_back(BlockRef(link, entry));
-                               last = &contested_blocks.back();
+                               contested_blocks.push_back(block);
                                continue;
                        }
                        else if(divert_track && (entry_conflict || exit_conflict))
@@ -1018,17 +983,17 @@ unsigned Train::reserve_more()
 
                        if(!reserved)
                        {
-                               pending_block = link;
+                               pending_block = &*block;
                                break;
                        }
                }
 
-               if(link->get_turnout_id())
+               if(block->get_turnout_id())
                {
-                       const Endpoint &track_ep = entry_ep.track->get_type().get_endpoints()[entry_ep.track_ep];
+                       const Endpoint &track_ep = track->get_type().get_endpoints()[track.entry()];
                        bool multiple_paths = (track_ep.paths&(track_ep.paths-1));
 
-                       if(multiple_paths || !last->block->get_turnout_id())
+                       if(multiple_paths || !last->get_turnout_id())
                        {
                                /* We can keep the blocks reserved so far if we are facing the
                                points or if there was no turnout immediately before this one.
@@ -1042,9 +1007,9 @@ unsigned Train::reserve_more()
                        // Figure out what path we'd like to take on the turnout
                        int path = -1;
                        for(list<RouteRef>::iterator i=cur_route; (path<0 && i!=routes.end()); ++i)
-                               path = i->route->get_turnout(link->get_turnout_id());
+                               path = i->route->get_turnout(block->get_turnout_id());
                        if(path<0)
-                               path = entry_ep.track->get_active_path();
+                               path = track->get_active_path();
                        if(!(track_ep.paths&(1<<path)))
                        {
                                for(unsigned i=0; track_ep.paths>>i; ++i)
@@ -1052,49 +1017,48 @@ unsigned Train::reserve_more()
                                                path = i;
                        }
 
-                       if(path!=static_cast<int>(entry_ep.track->get_active_path()))
+                       if(path!=static_cast<int>(track->get_active_path()))
                        {
                                // The turnout is set to wrong path - switch and wait for it
-                               pending_block = link;
-                               entry_ep.track->set_active_path(path);
+                               pending_block = &*block;
+                               track->set_active_path(path);
                                if(pending_block)
                                {
-                                       link->reserve(0);
+                                       block->reserve(0);
                                        break;
                                }
                        }
 
-                       if(multiple_paths && cur_route!=routes.end() && cur_route->diversion!=link->get_turnout_id())
+                       if(multiple_paths && cur_route!=routes.end() && cur_route->diversion!=block->get_turnout_id())
                                /* There's multiple paths to be taken and we are on a route - take
                                note of the diversion possibility */
-                               divert_track = entry_ep.track;
+                               divert_track = &*track;
                }
 
-               if(!contested_blocks.empty() && contested_blocks.front().block==link)
+               if(!contested_blocks.empty() && contested_blocks.front()==block)
                        contested_blocks.pop_front();
 
-               rsv_blocks.push_back(BlockRef(link, entry));
-               last = &rsv_blocks.back();
-               if(last->block->get_sensor_id())
+               rsv_blocks.push_back(block);
+               if(block->get_sensor_id())
                        ++nsens;
                if(nsens>0)
-                       dist += length;
+                       dist += block->get_path_length(block.entry());
        }
 
        // Unreserve blocks that were not good
-       while(!rsv_blocks.empty() && &rsv_blocks.back()!=good)
+       while(!rsv_blocks.empty() && rsv_blocks.back()!=good)
        {
-               rsv_blocks.back().block->reserve(0);
+               rsv_blocks.back()->reserve(0);
                rsv_blocks.pop_back();
        }
 
-       if(!rsv_blocks.empty() && &rsv_blocks.back()!=start)
+       if(!rsv_blocks.empty() && rsv_blocks.back()!=start)
                // We got some new blocks, so no longer need to yield
                yielding_to = 0;
 
        // Make any sensorless blocks at the beginning immediately current
-       list<BlockRef>::iterator i;
-       for(i=rsv_blocks.begin(); (i!=rsv_blocks.end() && !i->block->get_sensor_id()); ++i) ;
+       BlockList::iterator i;
+       for(i=rsv_blocks.begin(); (i!=rsv_blocks.end() && !(*i)->get_sensor_id()); ++i) ;
        if(i!=rsv_blocks.begin())
                cur_blocks.splice(cur_blocks.end(), rsv_blocks, rsv_blocks.begin(), i);
 
@@ -1112,12 +1076,12 @@ float Train::get_reserved_distance_until(const Block *until_block, bool back) co
        Vehicle &veh = *(reverse!=back ? vehicles.back() : vehicles.front());
        const VehicleType &vtype = veh.get_type();
 
-       Track *track = veh.get_track();
+       TrackIter track(veh.get_track(), veh.get_entry());
        if(!track)
                return 0;
 
-       list<BlockRef>::const_iterator block = cur_blocks.begin();
-       while(block!=rsv_blocks.end() && !block->block->has_track(*track))
+       BlockList::const_iterator block = cur_blocks.begin();
+       while(block!=rsv_blocks.end() && !(*block)->has_track(*track))
        {
                ++block;
                if(block==cur_blocks.end())
@@ -1127,26 +1091,23 @@ float Train::get_reserved_distance_until(const Block *until_block, bool back) co
                        block = rsv_blocks.begin();
                }
        }
-       if(block==rsv_blocks.end() || block->block==until_block)
+       if(block==rsv_blocks.end() || &**block==until_block)
                return 0;
 
-       unsigned entry = veh.get_entry();
-
        float result = veh.get_offset();
        if(reverse!=back)
-               entry = track->traverse(entry);
+               track = track.reverse();
        else
                result = track->get_type().get_path_length(track->get_active_path())-result;
        result -= vtype.get_length()/2;
 
        while(1)
        {
-               if(track->get_type().get_endpoints().size()<2)
+               track = track.next();
+               if(!track)
                        break;
 
-               Track *next = track->get_link(track->traverse(entry));
-
-               if(!block->block->has_track(*next))
+               if(!(*block)->has_track(*track))
                {
                        if(back)
                        {
@@ -1163,13 +1124,10 @@ float Train::get_reserved_distance_until(const Block *until_block, bool back) co
                                        break;
                        }
 
-                       if(block->block==until_block)
+                       if(&**block==until_block)
                                break;
                }
 
-               entry = next->get_endpoint_by_link(*track);
-               track = next;
-
                result += track->get_type().get_path_length(track->get_active_path());
        }
 
@@ -1252,26 +1210,26 @@ void Train::set_status(const string &s)
        signal_status_changed.emit(s);
 }
 
-void Train::release_blocks(list<BlockRef> &blocks)
+void Train::release_blocks(BlockList &blocks)
 {
        release_blocks(blocks, blocks.begin(), blocks.end());
 }
 
-void Train::release_blocks(list<BlockRef> &blocks, list<BlockRef>::iterator begin, list<BlockRef>::iterator end)
+void Train::release_blocks(BlockList &blocks, BlockList::iterator begin, BlockList::iterator end)
 {
        while(begin!=end)
        {
-               Block *block = begin->block;
+               Block &block = **begin;
                blocks.erase(begin++);
-               block->reserve(0);
+               block.reserve(0);
        }
 }
 
-void Train::reverse_blocks(list<BlockRef> &blocks) const
+void Train::reverse_blocks(BlockList &blocks) const
 {
        blocks.reverse();
-       for(list<BlockRef>::iterator i=blocks.begin(); i!=blocks.end(); ++i)
-               i->entry = i->block->traverse(i->entry);
+       for(BlockList::iterator i=blocks.begin(); i!=blocks.end(); ++i)
+               *i = i->reverse();
 }
 
 bool Train::advance_route(list<RouteRef>::iterator &iter, Track &track)
@@ -1299,9 +1257,9 @@ Route *Train::create_lead_route(Route *lead, const Route *target)
        }
 
        set<Track *> tracks;
-       for(list<BlockRef>::iterator i=cur_blocks.begin(); i!=rsv_blocks.end(); )
+       for(BlockList::iterator i=cur_blocks.begin(); i!=rsv_blocks.end(); )
        {
-               const set<Track *> &btracks = i->block->get_tracks();
+               const set<Track *> &btracks = (*i)->get_tracks();
                for(set<Track *>::const_iterator j=btracks.begin(); j!=btracks.end(); ++j)
                        if(!target || !target->has_track(**j))
                                tracks.insert(*j);
@@ -1318,20 +1276,16 @@ Route *Train::create_lead_route(Route *lead, const Route *target)
 bool Train::is_valid_diversion(const Route &diversion, Track &from, unsigned from_ep)
 {
        float diversion_len = 0;
-       Track *track = &from;
-       unsigned ep = from_ep;
+       TrackIter track(&from, from_ep);
        while(diversion.has_track(*track))
        {
-               unsigned path = 0;
-               if(track->get_turnout_id())
-                       path = diversion.get_turnout(track->get_turnout_id());
+               unsigned tid = track->get_turnout_id();
+               unsigned path = (tid ? diversion.get_turnout(tid) : 0);
                diversion_len += track->get_type().get_path_length(path);
 
-               Track *next = track->get_link(track->traverse(ep, path));
-               ep = next->get_endpoint_by_link(*track);
-               track = next;
+               track = track.next(path);
 
-               if(track==&from)
+               if(&*track==&from)
                        return false;
        }
 
@@ -1341,25 +1295,21 @@ bool Train::is_valid_diversion(const Route &diversion, Track &from, unsigned fro
 
        set<Track *> visited;
        float route_len = 0;
-       track = &from;
-       ep = from_ep;
+       track = TrackIter(&from, from_ep);
        while(1)
        {
-               unsigned path = 0;
-               if(track->get_turnout_id())
-                       path = route->route->get_turnout(track->get_turnout_id());
+               unsigned tid = track->get_turnout_id();
+               unsigned path = (tid ? route->route->get_turnout(tid) : 0);
                route_len += track->get_type().get_path_length(path);
 
-               if(track!=&from && diversion.has_track(*track))
+               if(&*track!=&from && diversion.has_track(*track))
                        break;
 
-               if(visited.count(track))
+               if(visited.count(&*track))
                        return false;
-               visited.insert(track);
+               visited.insert(&*track);
 
-               Track *next = track->get_link(track->traverse(ep, path));
-               ep = next->get_endpoint_by_link(*track);
-               track = next;
+               track = track.next(path);
 
                if(!advance_route(route, *track))
                        return false;
@@ -1369,25 +1319,6 @@ bool Train::is_valid_diversion(const Route &diversion, Track &from, unsigned fro
 }
 
 
-Train::BlockRef::BlockRef(Block *b, unsigned e):
-       block(b),
-       entry(e)
-{ }
-
-Train::BlockRef Train::BlockRef::next() const
-{
-       Block *blk = block->get_endpoints()[block->traverse(entry)].link;
-       if(!blk)
-               throw InvalidState("At end of line");
-
-       int ep = blk->get_endpoint_by_link(*block);
-       if(ep<0)
-               throw LogicError("Block links are inconsistent");
-
-       return BlockRef(blk, ep);
-}
-
-
 Train::RouteRef::RouteRef(const Route *r, unsigned d):
        route(r),
        diversion(d)
@@ -1425,10 +1356,9 @@ void Train::Loader::finish()
 {
        if(!obj.cur_blocks.empty())
        {
-               const BlockRef &blkref = obj.cur_blocks.front();
-               const Block::Endpoint &bep = blkref.block->get_endpoints()[blkref.entry];
+               TrackIter track = obj.cur_blocks.front().track_iter();
                float offset = 2*obj.layout.get_catalogue().get_scale();
-               obj.vehicles.back()->place(*bep.track, bep.track_ep, offset, Vehicle::BACK_BUFFER);
+               obj.vehicles.back()->place(*track, track.entry(), offset, Vehicle::BACK_BUFFER);
 
                obj.set_status("Stopped");
        }
@@ -1457,7 +1387,7 @@ void Train::Loader::block(unsigned id)
                entry = 0;
 
        blk->reserve(&obj);
-       obj.cur_blocks.push_back(BlockRef(blk, entry));
+       obj.cur_blocks.push_back(BlockIter(blk, entry));
 
        if(blk->get_sensor_id())
                obj.layout.get_driver().set_sensor(blk->get_sensor_id(), true);
index 7039c9ea87d9ec8484ee6b9de6c7d981b0044203..f267263cb9efbfa22cc804c4eb47c50ea5c972d9 100644 (file)
@@ -12,6 +12,7 @@ Distributed under the GPL
 #include <sigc++/trackable.h>
 #include <msp/time/timestamp.h>
 #include "block.h"
+#include "blockiter.h"
 #include "controller.h"
 
 namespace Marklin {
@@ -51,15 +52,6 @@ public:
        sigc::signal<void, const std::string &> signal_status_changed;
 
 private:
-       struct BlockRef
-       {
-               Block *block;
-               unsigned entry;
-
-               BlockRef(Block *, unsigned);
-               BlockRef next() const;
-       };
-
        struct RouteRef
        {
                const Route *route;
@@ -77,6 +69,8 @@ private:
                void add(float, float);
        };
 
+       typedef std::list<BlockIter> BlockList;
+
        Layout &layout;
        const VehicleType &loco_type;
        unsigned address;
@@ -84,8 +78,8 @@ private:
        int priority;
        const Train *yielding_to;
        std::vector<Vehicle *> vehicles;
-       std::list<BlockRef> cur_blocks;
-       std::list<BlockRef> rsv_blocks;
+       BlockList cur_blocks;
+       BlockList rsv_blocks;
        Block *pending_block;
        bool reserving;
        bool advancing;
@@ -171,9 +165,9 @@ private:
        unsigned find_speed(float) const;
        float get_travel_speed() const;
        void set_status(const std::string &);
-       void release_blocks(std::list<BlockRef> &);
-       void release_blocks(std::list<BlockRef> &, std::list<BlockRef>::iterator, std::list<BlockRef>::iterator);
-       void reverse_blocks(std::list<BlockRef> &) const;
+       void release_blocks(BlockList &);
+       void release_blocks(BlockList &, BlockList::iterator, BlockList::iterator);
+       void reverse_blocks(BlockList &) const;
        bool advance_route(std::list<RouteRef>::iterator &, Track &);
        Route *create_lead_route(Route *, const Route *);
        bool is_valid_diversion(const Route &, Track &, unsigned);
index 5a26f9294b665c8a5178696e482f78a8489f17dd..b54b531e0de2964e9fe1fb87590d4d3835ed4da7 100644 (file)
@@ -10,6 +10,7 @@ Distributed under the GPL
 #include "driver.h"
 #include "layout.h"
 #include "track.h"
+#include "trackiter.h"
 #include "tracktype.h"
 #include "vehicle.h"
 #include "vehicletype.h"
@@ -320,51 +321,36 @@ void Vehicle::TrackPosition::advance(float d)
        if(!track)
                return;
 
-       unsigned path = track->get_active_path();
-
        offs += d;
-       float path_len = track->get_type().get_path_length(path);
-       while(track && offs>=path_len)
+       TrackIter iter(track, ep);
+       while(iter)
        {
-               unsigned out = track->traverse(ep, path);
-               Track *next = track->get_link(out);
+               float path_len = iter->get_type().get_path_length(iter->get_active_path());
 
-               if(next)
+               if(offs>path_len)
                {
-                       ep = next->get_endpoint_by_link(*track);
-                       track = next;
-
                        offs -= path_len;
-                       path = track->get_active_path();
-                       path_len = track->get_type().get_path_length(path);
+                       iter = iter.next();
                }
                else
-                       track = 0;
+                       break;
        }
 
-       while(track && offs<0)
+       while(iter && offs<0)
        {
-               Track *prev = track->get_link(ep);
-               if(prev)
-               {
-                       unsigned in = prev->get_endpoint_by_link(*track);
-                       track = prev;
-
-                       path = track->get_active_path();
-                       ep = track->traverse(in, path);
+               iter = iter.flip().reverse();
 
-                       path_len = track->get_type().get_path_length(path);
+               if(iter)
+               {
+                       float path_len = iter->get_type().get_path_length(iter->get_active_path());
                        offs += path_len;
                }
-               else
-                       track = 0;
        }
 
+       track = iter.track();
+       ep = iter.entry();
        if(!track)
-       {
-               ep = 0;
                offs = 0;
-       }
 }
 
 TrackPoint Vehicle::TrackPosition::get_point() const