+#include <msp/core/maputils.h>
#include "catalogue.h"
#include "layout.h"
#include "route.h"
namespace R2C2 {
-TrainRoutePlanner::TrainRoutePlanner(Layout &layout)
+TrainRoutePlanner::TrainRoutePlanner(Layout &layout):
+ result(PENDING)
{
const map<unsigned, Train *> &trains = layout.get_trains();
for(map<unsigned, Train *>::const_iterator i=trains.begin(); i!=trains.end(); ++i)
{
steps.clear();
queue.clear();
+ result = PENDING;
queue.push_back(RoutingStep());
RoutingStep &start = queue.back();
}
if(goal)
+ {
create_routes(*goal);
+ result = COMPLETE;
+ }
+ else
+ result = FAILED;
+}
+
+const list<Route *> &TrainRoutePlanner::get_routes_for(const Train &train) const
+{
+ return get_train_info(train).routes;
+}
+
+const list<TrainRouter::SequencePoint> &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<TrainRoutingInfo>::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()
i->track_history[j] = 0;
}
- map<Track *, SequencingInfo *> sequenced_tracks;
+ map<Track *, TrainRouter::SequencePoint *> sequenced_tracks;
unsigned sequence = steps.size();
for(const RoutingStep *i=&goal; i; i=i->prev)
for(vector<TrainRoutingState>::const_iterator j=i->trains.begin(); j!=i->trains.end(); ++j)
history[0] = j->track.track();
bool waitable = j->track.endpoint().paths!=j->track->get_type().get_paths();
- map<Track *, SequencingInfo *>::iterator k = sequenced_tracks.find(j->track.track());
+ map<Track *, TrainRouter::SequencePoint *>::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<TrainRoutingInfo>::iterator i=routed_trains.begin(); i!=routed_trains.end(); ++i)
- {
- for(list<Route *>::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<SequencingInfo>::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()),
#include <vector>
#include <msp/time/timedelta.h>
#include "trackiter.h"
+#include "trainrouter.h"
namespace R2C2 {
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;
TrainRouter *router;
std::list<Route *> routes;
Track *track_history[3];
- std::list<SequencingInfo> sequence;
+ std::list<TrainRouter::SequencePoint> sequence;
TrainRoutingInfo(Train &);
};
std::vector<TrainRoutingInfo> routed_trains;
std::list<RoutingStep> steps;
std::list<RoutingStep> queue;
+ Result result;
public:
TrainRoutePlanner(Layout &);
void plan();
+ Result get_result() { return result; }
+ const std::list<Route *> &get_routes_for(const Train &) const;
+ const std::list<TrainRouter::SequencePoint> &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 &);
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));
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;
}
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
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
{
if(!destination)
throw logic_error("no metrics");
- else if(update_pending)
+ else if(metrics_stale)
throw logic_error("metrics are stale");
if(index<0)
void TrainRouter::set_departure_delay(const Time::TimeDelta &d)
{
delay = d;
- update_pending = true;
+ destination_changed = true;
}
void TrainRouter::message(const Message &msg)
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<Route *> &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<SequencePoint *>::iterator i=pending_sequence_checks.begin(); i!=pending_sequence_checks.end(); ++i)
if((*i)->preceding_train->get_ai_of_type<TrainRouter>()->get_current_sequence()>=(*i)->sequence_in)
return advance_route(iter, block);
}
-void TrainRouter::create_plans(Layout &layout)
+void TrainRouter::start_planning(Layout &layout)
{
+ RefPtr<TrainRoutePlanner> planner = new TrainRoutePlanner(layout);
+
const map<unsigned, Train *> &trains = layout.get_trains();
for(map<unsigned, Train *>::const_iterator i=trains.begin(); i!=trains.end(); ++i)
if(TrainRouter *router = i->second->get_ai_of_type<TrainRouter>())
{
- 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();
}
class Track;
class TrackChain;
class TrainRouteMetric;
+class TrainRoutePlanner;
class TrainRouter: public TrainAI
{
sigc::signal<void, const TrackChain *> signal_arrived;
sigc::signal<void, const TrackChain *> signal_waypoint_reached;
-private:
struct SequencePoint
{
Block *block;
SequencePoint(Block &, unsigned);
};
+private:
typedef std::list<const Route *> RouteList;
int priority;
unsigned arriving;
const TrackChain *destination;
std::vector<const TrackChain *> waypoints;
+ bool destination_changed;
std::vector<TrainRouteMetric *> metrics;
+ bool metrics_stale;
std::list<SequencePoint> sequence_points;
std::list<SequencePoint *> pending_sequence_checks;
unsigned current_sequence;
Msp::Time::TimeDelta delay;
-
- bool update_pending;
+ Msp::RefPtr<TrainRoutePlanner> planner;
public:
TrainRouter(Train &);
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;
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