]> git.tdb.fi Git - r2c2.git/blobdiff - source/libmarklin/train.cpp
Move Endpoint inside TrackType
[r2c2.git] / source / libmarklin / train.cpp
index 5bc50d85ff23ee5011535e34e5e6142f6b08fccc..11ec776497e436c64eea49d3a8bcaecdf1e27e11 100644 (file)
@@ -16,6 +16,7 @@ Distributed under the GPL
 #include "route.h"
 #include "simplecontroller.h"
 #include "timetable.h"
 #include "route.h"
 #include "simplecontroller.h"
 #include "timetable.h"
+#include "trackiter.h"
 #include "tracktype.h"
 #include "train.h"
 #include "vehicle.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())
        {
 
        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);
                }
                        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));
        }
 
                        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)
 {
 
 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);
                {
                        signal_arrived.emit();
                        set_route(0);
@@ -246,11 +244,9 @@ void Train::go_to(Track &to)
 
        free_noncritical_blocks();
 
 
        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);
 }
        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();
        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)
        {
        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;
 
                if(visited.count(entry_ep.track))
                        return false;
@@ -309,7 +302,7 @@ bool Train::divert(Track &from)
                        break;
                }
 
                        break;
                }
 
-       Track *track = from.get_link(from.traverse(from_ep, path));
+       TrackIter track = TrackIter(&from, from_ep).next(path);
        if(!track)
                return false;
 
        if(!track)
                return false;
 
@@ -342,22 +335,17 @@ bool Train::divert(Track &from)
        list<RouteRef>::iterator end = routes.end();
        while(1)
        {
        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)
                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;
                                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");
 
                        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)
        }
 
        if(route==end)
@@ -397,14 +385,11 @@ void Train::place(Block &block, unsigned entry)
                return;
        }
 
                return;
        }
 
-       cur_blocks.push_back(BlockRef(&block, entry));
+       cur_blocks.push_back(BlockIter(&block, entry));
        if(reverse)
        {
        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
        {
        }
        else
        {
@@ -437,16 +422,16 @@ bool Train::free_block(Block &block)
                return false;
 
        unsigned nsens = 0;
                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;
                }
                {
                        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;
        }
 
                        ++nsens;
        }
 
@@ -469,10 +454,10 @@ void Train::free_noncritical_blocks()
 
        Vehicle &veh = *(reverse ? vehicles.back() : vehicles.front());
 
 
        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;
        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())
        {
                ++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)
        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;
        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)
        {
        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())
                {
                        ++block;
                        if(block==cur_blocks.end())
@@ -514,7 +496,7 @@ void Train::free_noncritical_blocks()
                                return;
                        }
 
                                return;
                        }
 
-                       if(in_rsv && block->block->get_sensor_id())
+                       if(in_rsv && (*block)->get_sensor_id())
                                ++nsens;
                }
 
                                ++nsens;
                }
 
@@ -524,12 +506,12 @@ void Train::free_noncritical_blocks()
 
 int Train::get_entry_to_block(Block &block) const
 {
 
 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;
 }
 
        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;
                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)
 
                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);
        }
 
                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())
                {
 
                if(dist>10*layout.get_catalogue().get_scale())
                {
-                       cur_blocks.front().block->reserve(0);
+                       cur_blocks.front()->reserve(0);
                        cur_blocks.pop_front();
                }
        }
                        cur_blocks.pop_front();
                }
        }
@@ -641,15 +623,15 @@ void Train::save(list<DataFile::Statement> &st) const
 
        if(!cur_blocks.empty())
        {
 
        if(!cur_blocks.empty())
        {
-               list<BlockRef> blocks = cur_blocks;
+               BlockList blocks = cur_blocks;
                if(reverse)
                        reverse_blocks(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()));
 
                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())
        }
 
        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
        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)
                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;
                                {
                                        if(result==0)
                                                result = 2;
@@ -737,23 +719,20 @@ void Train::sensor_event(unsigned addr, bool state)
                        }
 
                        travel_dist = 0;
                        }
 
                        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)
                                        {
                                        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
                                        }
                                        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();
                                }
                        }
                        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();
                        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?
                                        {
                                                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
                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;
                                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
                                {
                                        break;
                                else
                                {
@@ -846,12 +825,12 @@ unsigned Train::reserve_more()
        if(!active)
                return 0;
 
        if(!active)
                return 0;
 
-       BlockRef *start = 0;
+       BlockIter start;
        if(!rsv_blocks.empty())
        if(!rsv_blocks.empty())
-               start = &rsv_blocks.back();
+               start = rsv_blocks.back();
        else if(!cur_blocks.empty())
        else if(!cur_blocks.empty())
-               start = &cur_blocks.back();
-       if(!start)
+               start = cur_blocks.back();
+       else
                return 0;
 
        pending_block = 0;
                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;
        // 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)
                        ++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();
        }
        
        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;
 
 
        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;
        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())
        {
 
        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;
 
                        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(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)
                        {
                                // Keep the blocks if we arrived at the end of the route
                                if(!blocking_train)
@@ -925,10 +890,10 @@ unsigned Train::reserve_more()
                                break;
                        }
                }
                                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();
 
                        cur_route = routes.begin();
 
-               if(link->get_endpoints().size()<2)
+               if(block->get_endpoints().size()<2)
                {
                        if(!blocking_train)
                        {
                {
                        if(!blocking_train)
                        {
@@ -941,14 +906,14 @@ unsigned Train::reserve_more()
 
                if(blocking_train)
                {
 
                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
                                {
                                        // Roll back and start actually reserving the blocks
-                                       last = &rsv_blocks.back();
+                                       block = rsv_blocks.back();
                                        cur_route = routes.begin();
                                        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;
                                        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);
                                else
                                {
                                        yield_to(*blocking_train);
-                                       pending_block = contested_blocks.front().block;
+                                       pending_block = contested_blocks.front().block();
                                        try_divert = divert_track;
                                        break;
                                }
                        }
                        else
                        {
                                        try_divert = divert_track;
                                        break;
                                }
                        }
                        else
                        {
-                               contested_blocks.push_back(BlockRef(link, entry));
-                               last = &contested_blocks.back();
+                               contested_blocks.push_back(block);
                                continue;
                        }
                }
 
                                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. */
                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");
 
                        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. */
                        {
                                /* 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 */
                        {
                                /* 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)))
                        {
                        }
                        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();
                                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))
                                continue;
                        }
                        else if(divert_track && (entry_conflict || exit_conflict))
@@ -1018,17 +983,17 @@ unsigned Train::reserve_more()
 
                        if(!reserved)
                        {
 
                        if(!reserved)
                        {
-                               pending_block = link;
+                               pending_block = &*block;
                                break;
                        }
                }
 
                                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 TrackType::Endpoint &track_ep = track->get_type().get_endpoints()[track.entry()];
                        bool multiple_paths = (track_ep.paths&(track_ep.paths-1));
 
                        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.
                        {
                                /* 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)
                        // 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)
                        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)
                        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;
                        }
 
                                                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
                        {
                                // 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)
                                {
                                if(pending_block)
                                {
-                                       link->reserve(0);
+                                       block->reserve(0);
                                        break;
                                }
                        }
 
                                        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 */
                                /* 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();
 
                        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)
                        ++nsens;
                if(nsens>0)
-                       dist += length;
+                       dist += block->get_path_length(block.entry());
        }
 
        // Unreserve blocks that were not good
        }
 
        // 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();
        }
 
                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
                // 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);
 
        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();
 
        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;
 
        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())
        {
                ++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();
                }
        }
                        block = rsv_blocks.begin();
                }
        }
-       if(block==rsv_blocks.end() || block->block==until_block)
+       if(block==rsv_blocks.end() || &**block==until_block)
                return 0;
 
                return 0;
 
-       unsigned entry = veh.get_entry();
-
        float result = veh.get_offset();
        if(reverse!=back)
        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)
        {
        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;
 
                        break;
 
-               Track *next = track->get_link(track->traverse(entry));
-
-               if(!block->block->has_track(*next))
+               if(!(*block)->has_track(*track))
                {
                        if(back)
                        {
                {
                        if(back)
                        {
@@ -1163,13 +1124,10 @@ float Train::get_reserved_distance_until(const Block *until_block, bool back) co
                                        break;
                        }
 
                                        break;
                        }
 
-                       if(block->block==until_block)
+                       if(&**block==until_block)
                                break;
                }
 
                                break;
                }
 
-               entry = next->get_endpoint_by_link(*track);
-               track = next;
-
                result += track->get_type().get_path_length(track->get_active_path());
        }
 
                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);
 }
 
        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());
 }
 
 {
        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)
        {
 {
        while(begin!=end)
        {
-               Block *block = begin->block;
+               Block &block = **begin;
                blocks.erase(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();
 {
        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)
 }
 
 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;
        }
 
        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);
                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;
 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))
        {
        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);
 
                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;
        }
 
                        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;
 
        set<Track *> visited;
        float route_len = 0;
-       track = &from;
-       ep = from_ep;
+       track = TrackIter(&from, from_ep);
        while(1)
        {
        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);
 
                route_len += track->get_type().get_path_length(path);
 
-               if(track!=&from && diversion.has_track(*track))
+               if(&*track!=&from && diversion.has_track(*track))
                        break;
 
                        break;
 
-               if(visited.count(track))
+               if(visited.count(&*track))
                        return false;
                        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;
 
                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)
 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())
        {
 {
        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();
                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");
        }
 
                obj.set_status("Stopped");
        }
@@ -1457,7 +1387,7 @@ void Train::Loader::block(unsigned id)
                entry = 0;
 
        blk->reserve(&obj);
                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);
 
        if(blk->get_sensor_id())
                obj.layout.get_driver().set_sensor(blk->get_sensor_id(), true);