From 3de7ae761b9a1fd1c1cd40457cc7067f4cf57c36 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Mon, 14 Apr 2014 08:01:36 +0300 Subject: [PATCH] Redesign the interface between TrainRouter and TrainRoutePlanner This will make it easier to move planning to a separate thread in the future. --- source/libr2c2/trainrouteplanner.cpp | 68 ++++++++++---------- source/libr2c2/trainrouteplanner.h | 28 ++++---- source/libr2c2/trainrouter.cpp | 96 +++++++++++++++------------- source/libr2c2/trainrouter.h | 16 +++-- 4 files changed, 108 insertions(+), 100 deletions(-) diff --git a/source/libr2c2/trainrouteplanner.cpp b/source/libr2c2/trainrouteplanner.cpp index 8126ec5..7ee655a 100644 --- a/source/libr2c2/trainrouteplanner.cpp +++ b/source/libr2c2/trainrouteplanner.cpp @@ -1,3 +1,4 @@ +#include #include "catalogue.h" #include "layout.h" #include "route.h" @@ -12,7 +13,8 @@ using namespace Msp; namespace R2C2 { -TrainRoutePlanner::TrainRoutePlanner(Layout &layout) +TrainRoutePlanner::TrainRoutePlanner(Layout &layout): + result(PENDING) { const map &trains = layout.get_trains(); for(map::const_iterator i=trains.begin(); i!=trains.end(); ++i) @@ -27,6 +29,7 @@ void TrainRoutePlanner::plan() { steps.clear(); queue.clear(); + result = PENDING; queue.push_back(RoutingStep()); RoutingStep &start = queue.back(); @@ -48,7 +51,31 @@ void TrainRoutePlanner::plan() } if(goal) + { create_routes(*goal); + result = COMPLETE; + } + else + result = FAILED; +} + +const list &TrainRoutePlanner::get_routes_for(const Train &train) const +{ + return get_train_info(train).routes; +} + +const list &TrainRoutePlanner::get_sequence_for(const Train &train) const +{ + return get_train_info(train).sequence; +} + +const TrainRoutePlanner::TrainRoutingInfo &TrainRoutePlanner::get_train_info(const Train &train) const +{ + for(vector::const_iterator i=routed_trains.begin(); i!=routed_trains.end(); ++i) + if(i->train==&train) + return *i; + + throw key_error(train.get_name()); } const TrainRoutePlanner::RoutingStep &TrainRoutePlanner::get_step() @@ -75,7 +102,7 @@ void TrainRoutePlanner::create_routes(const RoutingStep &goal) i->track_history[j] = 0; } - map sequenced_tracks; + map sequenced_tracks; unsigned sequence = steps.size(); for(const RoutingStep *i=&goal; i; i=i->prev) for(vector::const_iterator j=i->trains.begin(); j!=i->trains.end(); ++j) @@ -119,56 +146,29 @@ void TrainRoutePlanner::create_routes(const RoutingStep &goal) history[0] = j->track.track(); bool waitable = j->track.endpoint().paths!=j->track->get_type().get_paths(); - map::iterator k = sequenced_tracks.find(j->track.track()); + map::iterator k = sequenced_tracks.find(j->track.track()); if(k!=sequenced_tracks.end()) { - if(!k->second->preceding) + if(!k->second->preceding_train) { - k->second->preceding = j->info; + k->second->preceding_train = j->info->train; k->second->sequence_in = sequence; } - j->info->sequence.push_front(SequencingInfo(j->track.track(), sequence)); + j->info->sequence.push_front(TrainRouter::SequencePoint(j->track->get_block(), sequence)); if(waitable) k->second = &j->info->sequence.front(); --sequence; } else if(waitable) { - j->info->sequence.push_front(SequencingInfo(j->track.track(), sequence)); + j->info->sequence.push_front(TrainRouter::SequencePoint(j->track->get_block(), sequence)); sequenced_tracks[j->track.track()] = &j->info->sequence.front(); --sequence; } } - - for(vector::iterator i=routed_trains.begin(); i!=routed_trains.end(); ++i) - { - for(list::iterator j=i->routes.begin(); j!=i->routes.end(); ++j) - { - if(j==i->routes.begin()) - i->router->set_route(*j); - else - i->router->add_route(**j); - } - - for(list::iterator j=i->sequence.begin(); j!=i->sequence.end(); ++j) - { - if(j->preceding && j->preceding!=&*i) - i->router->add_sequence_point(j->track->get_block(), *j->preceding->train, j->sequence_in, j->sequence_out); - else - i->router->add_sequence_point(j->track->get_block(), j->sequence_out); - } - } } -TrainRoutePlanner::SequencingInfo::SequencingInfo(Track *t, unsigned o): - track(t), - preceding(0), - sequence_in(0), - sequence_out(o) -{ } - - TrainRoutePlanner::TrainRoutingInfo::TrainRoutingInfo(Train &t): train(&t), speed(train->get_maximum_speed()), diff --git a/source/libr2c2/trainrouteplanner.h b/source/libr2c2/trainrouteplanner.h index c6ca741..f5bbf57 100644 --- a/source/libr2c2/trainrouteplanner.h +++ b/source/libr2c2/trainrouteplanner.h @@ -5,6 +5,7 @@ #include #include #include "trackiter.h" +#include "trainrouter.h" namespace R2C2 { @@ -12,24 +13,20 @@ class Layout; class Route; class Track; class Train; -class TrainRouter; class TrainRoutePlanner { -private: - struct TrainRoutingState; - struct TrainRoutingInfo; - - struct SequencingInfo +public: + enum Result { - Track *track; - TrainRoutingInfo *preceding; - unsigned sequence_in; - unsigned sequence_out; - - SequencingInfo(Track *, unsigned); + PENDING, + COMPLETE, + FAILED }; +private: + struct TrainRoutingState; + struct TrainRoutingInfo { Train *train; @@ -37,7 +34,7 @@ private: TrainRouter *router; std::list routes; Track *track_history[3]; - std::list sequence; + std::list sequence; TrainRoutingInfo(Train &); }; @@ -118,12 +115,17 @@ private: std::vector routed_trains; std::list steps; std::list queue; + Result result; public: TrainRoutePlanner(Layout &); void plan(); + Result get_result() { return result; } + const std::list &get_routes_for(const Train &) const; + const std::list &get_sequence_for(const Train &) const; private: + const TrainRoutingInfo &get_train_info(const Train &) const; const RoutingStep &get_step(); void add_steps(const RoutingStep &); void create_routes(const RoutingStep &); diff --git a/source/libr2c2/trainrouter.cpp b/source/libr2c2/trainrouter.cpp index 8b3433c..2fac984 100644 --- a/source/libr2c2/trainrouter.cpp +++ b/source/libr2c2/trainrouter.cpp @@ -17,7 +17,8 @@ TrainRouter::TrainRouter(Train &t): priority(0), arriving(0), destination(0), - update_pending(false) + destination_changed(false), + metrics_stale(false) { train.get_layout().signal_block_reserved.connect(sigc::mem_fun(this, &TrainRouter::block_reserved)); train.signal_advanced.connect(sigc::mem_fun(this, &TrainRouter::train_advanced)); @@ -60,36 +61,14 @@ bool TrainRouter::set_route(const Route *r) routes.push_back(lead); if(r) routes.push_back(r); - train.stop_at(0); - arriving = 0; - /* TODO destination should also be cleared when manually setting a different - route, but not when the planner calls this. */ - if(!r) - { - destination = 0; - waypoints.clear(); - } + destination = 0; + waypoints.clear(); sequence_points.clear(); pending_sequence_checks.clear(); current_sequence = 0; - train.refresh_blocks_from(*fncb); - - const Route *route = get_route(); - signal_route_changed.emit(route); - signal_event.emit(Message("route-changed", route)); - - return true; -} - -bool TrainRouter::add_route(const Route &r) -{ - if(routes.empty()) - return set_route(&r); - - // TODO Check that it can be reached from previous routes - routes.push_back(&r); + route_changed(); return true; } @@ -101,23 +80,23 @@ const Route *TrainRouter::get_route() const return routes.front(); } -void TrainRouter::add_sequence_point(Block &b, unsigned o) +void TrainRouter::route_changed() { - sequence_points.push_back(SequencePoint(b, o)); -} + train.stop_at(0); + arriving = 0; + BlockIter fncb = train.get_first_noncritical_block(); + train.refresh_blocks_from(*fncb); -void TrainRouter::add_sequence_point(Block &b, Train &t, unsigned i, unsigned o) -{ - SequencePoint sp(b, o); - sp.preceding_train = &t; - sp.sequence_in = i; - sequence_points.push_back(sp); + const Route *route = get_route(); + signal_route_changed.emit(route); + signal_event.emit(Message("route-changed", route)); } void TrainRouter::set_destination(const TrackChain &d) { destination = &d; - update_pending = true; + destination_changed = true; + metrics_stale = true; } bool TrainRouter::is_destination(Track &track) const @@ -131,7 +110,8 @@ bool TrainRouter::is_destination(Track &track) const void TrainRouter::add_waypoint(const TrackChain &wp) { waypoints.push_back(&wp); - update_pending = true; + destination_changed = true; + metrics_stale = true; } bool TrainRouter::is_waypoint(unsigned index, Track &track) const @@ -146,7 +126,7 @@ const TrainRouteMetric &TrainRouter::get_metric(int index) const { if(!destination) throw logic_error("no metrics"); - else if(update_pending) + else if(metrics_stale) throw logic_error("metrics are stale"); if(index<0) @@ -160,7 +140,7 @@ const TrainRouteMetric &TrainRouter::get_metric(int index) const void TrainRouter::set_departure_delay(const Time::TimeDelta &d) { delay = d; - update_pending = true; + destination_changed = true; } void TrainRouter::message(const Message &msg) @@ -201,8 +181,28 @@ void TrainRouter::tick(const Time::TimeDelta &dt) delay = Time::zero; } - if(update_pending) - create_plans(train.get_layout()); + if(destination_changed) + { + if(!planner) + start_planning(train.get_layout()); + else if(planner->get_result()!=TrainRoutePlanner::PENDING) + { + destination_changed = false; + if(planner->get_result()==TrainRoutePlanner::COMPLETE) + { + const list &planned_routes = planner->get_routes_for(train); + routes.clear(); + routes.push_back(create_lead_route(0, planned_routes.front())); + routes.insert(routes.end(), planned_routes.begin(), planned_routes.end()); + sequence_points = planner->get_sequence_for(train); + pending_sequence_checks.clear(); + current_sequence = 0; + + route_changed(); + } + planner = 0; + } + } for(list::iterator i=pending_sequence_checks.begin(); i!=pending_sequence_checks.end(); ++i) if((*i)->preceding_train->get_ai_of_type()->get_current_sequence()>=(*i)->sequence_in) @@ -435,19 +435,23 @@ bool TrainRouter::is_on_route(const Block &block) return advance_route(iter, block); } -void TrainRouter::create_plans(Layout &layout) +void TrainRouter::start_planning(Layout &layout) { + RefPtr planner = new TrainRoutePlanner(layout); + const map &trains = layout.get_trains(); for(map::const_iterator i=trains.begin(); i!=trains.end(); ++i) if(TrainRouter *router = i->second->get_ai_of_type()) { - if(router->update_pending) + if(router->metrics_stale) + { router->create_metrics(); - router->update_pending = false; + router->metrics_stale = false; + } + router->planner = planner; } - TrainRoutePlanner planner(layout); - planner.plan(); + planner->plan(); } diff --git a/source/libr2c2/trainrouter.h b/source/libr2c2/trainrouter.h index 6f697f9..cbaa520 100644 --- a/source/libr2c2/trainrouter.h +++ b/source/libr2c2/trainrouter.h @@ -12,6 +12,7 @@ class Layout; class Track; class TrackChain; class TrainRouteMetric; +class TrainRoutePlanner; class TrainRouter: public TrainAI { @@ -28,7 +29,6 @@ public: sigc::signal signal_arrived; sigc::signal signal_waypoint_reached; -private: struct SequencePoint { Block *block; @@ -39,6 +39,7 @@ private: SequencePoint(Block &, unsigned); }; +private: typedef std::list RouteList; int priority; @@ -46,13 +47,14 @@ private: unsigned arriving; const TrackChain *destination; std::vector waypoints; + bool destination_changed; std::vector metrics; + bool metrics_stale; std::list sequence_points; std::list pending_sequence_checks; unsigned current_sequence; Msp::Time::TimeDelta delay; - - bool update_pending; + Msp::RefPtr planner; public: TrainRouter(Train &); @@ -62,12 +64,12 @@ public: int get_priority() const { return priority; } bool set_route(const Route *); - bool add_route(const Route &); const Route *get_route() const; - void add_sequence_point(Block &, unsigned); - void add_sequence_point(Block &, Train &, unsigned, unsigned); unsigned get_current_sequence() const { return current_sequence; } +private: + void route_changed(); +public: void set_destination(const TrackChain &); const TrackChain *get_destination() const { return destination; } bool is_destination(Track &) const; @@ -93,7 +95,7 @@ private: bool advance_route(RouteList::iterator &, const Block &); bool is_on_route(const Block &); - static void create_plans(Layout &); + static void start_planning(Layout &); }; } // namespace R2C2 -- 2.45.2