From 2bb6ce8ada216c0b2caa48f4639d03f2c581098e Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Mon, 25 Oct 2010 13:30:36 +0000 Subject: [PATCH] Add TrackIter and BlockIter classes Remove the traverse functions in favor of the iterators --- source/engineer/trainpanel.cpp | 16 +- source/libmarklin/block.cpp | 50 ++--- source/libmarklin/block.h | 3 +- source/libmarklin/blockiter.cpp | 122 +++++++++++ source/libmarklin/blockiter.h | 50 +++++ source/libmarklin/route.cpp | 25 +-- source/libmarklin/track.cpp | 31 --- source/libmarklin/track.h | 2 - source/libmarklin/trackiter.cpp | 112 ++++++++++ source/libmarklin/trackiter.h | 51 +++++ source/libmarklin/train.cpp | 374 +++++++++++++------------------- source/libmarklin/train.h | 22 +- source/libmarklin/vehicle.cpp | 42 ++-- 13 files changed, 544 insertions(+), 356 deletions(-) create mode 100644 source/libmarklin/blockiter.cpp create mode 100644 source/libmarklin/blockiter.h create mode 100644 source/libmarklin/trackiter.cpp create mode 100644 source/libmarklin/trackiter.h diff --git a/source/engineer/trainpanel.cpp b/source/engineer/trainpanel.cpp index a0dbbee..96aa00d 100644 --- a/source/engineer/trainpanel.cpp +++ b/source/engineer/trainpanel.cpp @@ -8,6 +8,7 @@ Distributed under the GPL #include #include #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 &eps = block.get_endpoints(); bool ok = false; for(unsigned i=0; (!ok && iget_links()[ep]; - ep = next->traverse(next->get_endpoint_by_link(*track), 0); - track = next; - if(!block.has_track(*track)) - break; - } + + iter = iter.flip().reverse(); } } diff --git a/source/libmarklin/block.cpp b/source/libmarklin/block.cpp index ec07947..952fe50 100644 --- a/source/libmarklin/block.cpp +++ b/source/libmarklin/block.cpp @@ -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(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) diff --git a/source/libmarklin/block.h b/source/libmarklin/block.h index 23a48c0..cf5f3e7 100644 --- a/source/libmarklin/block.h +++ b/source/libmarklin/block.h @@ -51,8 +51,7 @@ public: bool has_track(Track &) const; const std::vector &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 index 0000000..7618e4b --- /dev/null +++ b/source/libmarklin/blockiter.cpp @@ -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 +#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 &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; iget_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 index 0000000..2b8256f --- /dev/null +++ b/source/libmarklin/blockiter.h @@ -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 diff --git a/source/libmarklin/route.cpp b/source/libmarklin/route.cpp index d4fcf80..6dc7ae5 100644 --- a/source/libmarklin/route.cpp +++ b/source/libmarklin/route.cpp @@ -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 &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; } } diff --git a/source/libmarklin/track.cpp b/source/libmarklin/track.cpp index 5f1ca43..6ec3c3b 100644 --- a/source/libmarklin/track.cpp +++ b/source/libmarklin/track.cpp @@ -293,37 +293,6 @@ Track *Track::get_link(unsigned i) const return links[i]; } -unsigned Track::traverse(unsigned i, unsigned path) const -{ - const vector &eps = type.get_endpoints(); - if(i>=eps.size()) - throw InvalidParameterValue("Endpoint index out of range"); - - const Endpoint &ep = eps[i]; - - if(ep.paths&(1< &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 index 0000000..e8b327b --- /dev/null +++ b/source/libmarklin/trackiter.cpp @@ -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 +#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 &eps = _track->get_type().get_endpoints(); + + // Find an endpoint that's connected to the entry and has the requested path + for(unsigned i=0; iget_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 index 0000000..c91a768 --- /dev/null +++ b/source/libmarklin/trackiter.h @@ -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 +#include + +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 diff --git a/source/libmarklin/train.cpp b/source/libmarklin/train.cpp index 5bc50d8..cdb8e67 100644 --- a/source/libmarklin/train.cpp +++ b/source/libmarklin/train.cpp @@ -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::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::iterator route = routes.begin(); - Block *block = cur_blocks.back().block; - unsigned entry = cur_blocks.back().entry; + BlockIter block = cur_blocks.back(); set 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::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::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::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::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::const_iterator i=cur_blocks.begin(); i!=cur_blocks.end(); ++i) - if(i->block==&block) - return i->entry; - for(list::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::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 &st) const if(!cur_blocks.empty()) { - list 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::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::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::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 &rtracks = (++routes.begin())->route->get_tracks(); - for(list::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::iterator end = cur_blocks.begin(); - for(list::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::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::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 contested_blocks; + BlockList contested_blocks; SetFlag setf(reserving); while(good_sens<3 || good_distroute : 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(entry)==link->traverse(other_entry)); - bool exit_conflict = (link->traverse(entry)==static_cast(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(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_prioget_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::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<>i; ++i) @@ -1052,49 +1017,48 @@ unsigned Train::reserve_more() path = i; } - if(path!=static_cast(entry_ep.track->get_active_path())) + if(path!=static_cast(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::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::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 &blocks) +void Train::release_blocks(BlockList &blocks) { release_blocks(blocks, blocks.begin(), blocks.end()); } -void Train::release_blocks(list &blocks, list::iterator begin, list::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 &blocks) const +void Train::reverse_blocks(BlockList &blocks) const { blocks.reverse(); - for(list::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::iterator &iter, Track &track) @@ -1299,9 +1257,9 @@ Route *Train::create_lead_route(Route *lead, const Route *target) } set tracks; - for(list::iterator i=cur_blocks.begin(); i!=rsv_blocks.end(); ) + for(BlockList::iterator i=cur_blocks.begin(); i!=rsv_blocks.end(); ) { - const set &btracks = i->block->get_tracks(); + const set &btracks = (*i)->get_tracks(); for(set::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 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); diff --git a/source/libmarklin/train.h b/source/libmarklin/train.h index 7039c9e..f267263 100644 --- a/source/libmarklin/train.h +++ b/source/libmarklin/train.h @@ -12,6 +12,7 @@ Distributed under the GPL #include #include #include "block.h" +#include "blockiter.h" #include "controller.h" namespace Marklin { @@ -51,15 +52,6 @@ public: sigc::signal 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 BlockList; + Layout &layout; const VehicleType &loco_type; unsigned address; @@ -84,8 +78,8 @@ private: int priority; const Train *yielding_to; std::vector vehicles; - std::list cur_blocks; - std::list 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 &); - void release_blocks(std::list &, std::list::iterator, std::list::iterator); - void reverse_blocks(std::list &) const; + void release_blocks(BlockList &); + void release_blocks(BlockList &, BlockList::iterator, BlockList::iterator); + void reverse_blocks(BlockList &) const; bool advance_route(std::list::iterator &, Track &); Route *create_lead_route(Route *, const Route *); bool is_valid_diversion(const Route &, Track &, unsigned); diff --git a/source/libmarklin/vehicle.cpp b/source/libmarklin/vehicle.cpp index 5a26f92..b54b531 100644 --- a/source/libmarklin/vehicle.cpp +++ b/source/libmarklin/vehicle.cpp @@ -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 -- 2.43.0