]> git.tdb.fi Git - r2c2.git/blobdiff - source/libr2c2/trainrouter.cpp
New routing system for trains
[r2c2.git] / source / libr2c2 / trainrouter.cpp
index 6e588e7a7ac4302c97db28f968fa1c8d04a01b27..77d6f71c8a082f9108921b3d3051b58b4fada51f 100644 (file)
@@ -2,6 +2,7 @@
 #include "route.h"
 #include "trackiter.h"
 #include "train.h"
+#include "trainrouteplanner.h"
 #include "trainrouter.h"
 #include "zone.h"
 
@@ -14,7 +15,9 @@ TrainRouter::TrainRouter(Train &t):
        TrainAI(t),
        priority(0),
        arriving(false),
-       yielding_to(0)
+       dest_zone(0),
+       dest_block(0),
+       update_pending(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));
@@ -25,11 +28,6 @@ void TrainRouter::set_priority(int p)
        priority = p;
 }
 
-void TrainRouter::yield_to(const Train &t)
-{
-       yielding_to = &t;
-}
-
 bool TrainRouter::set_route(const Route *r)
 {
        train.free_noncritical_blocks();
@@ -67,65 +65,48 @@ bool TrainRouter::set_route(const Route *r)
        return true;
 }
 
-bool TrainRouter::go_to(Track &to)
+void TrainRouter::add_wait(Block &block, Train *tr)
 {
-       if(!train.get_speed())
-       {
-               for(BlockIter i=train.get_tail_block(); (i && i->get_train()==&train); i=i.next())
-                       if(i->has_track(to))
-                       {
-                               signal_arrived.emit();
-                               signal_event.emit(Message("arrived"));
-                               return set_route(0);
-                       }
-       }
-
-       train.free_noncritical_blocks();
-
-       TrackIter next = train.get_head_block().next().track_iter();
-
-       Route *route = Route::find(next, to);
-       if(!route)
-               return false;
-       create_lead_route(route, route);
-       return set_route(route);
+       Wait wait;
+       wait.block = █
+       wait.train = tr;
+       waits.push_back(wait);
 }
 
-bool TrainRouter::go_to(const Zone &to)
+const Route *TrainRouter::get_route() const
 {
-       set<Track *> tracks;
-       for(BlockIter i=train.get_tail_block(); (i && i->get_train()==&train); i=i.next())
-               tracks.insert(i->get_tracks().begin(), i->get_tracks().end());
-
-       const Zone::TrackSet &ztracks = to.get_tracks();
-       unsigned union_size = 0;
-       for(Zone::TrackSet::const_iterator i=ztracks.begin(); i!=ztracks.end(); ++i)
-               union_size += tracks.count(*i);
-
-       if(union_size==tracks.size() || union_size==ztracks.size())
-       {
-               signal_arrived.emit();
-               signal_event.emit(Message("arrived"));
-               return set_route(0);
-       }
+       if(routes.empty())
+               return 0;
+       return routes.front();
+}
 
-       train.free_noncritical_blocks();
+void TrainRouter::set_destination(const Zone &zone)
+{
+       dest_zone = &zone;
+       dest_block = 0;
+       update_pending = true;
+}
 
-       TrackIter next = train.get_head_block().next().track_iter();
+void TrainRouter::set_destination(const Block &block)
+{
+       dest_zone = 0;
+       dest_block = &block;
+       update_pending = true;
+}
 
-       Route *route = Route::find(next, to);
-       if(!route)
-               return false;
-       create_lead_route(route, route);
-       route->add_tracks(ztracks);
-       return set_route(route);
+bool TrainRouter::has_destination() const
+{
+       return dest_zone || dest_block;
 }
 
-const Route *TrainRouter::get_route() const
+bool TrainRouter::is_destination(Track &track) const
 {
-       if(routes.empty())
-               return 0;
-       return routes.front();
+       if(dest_zone)
+               return dest_zone->has_track(track);
+       else if(dest_block)
+               return dest_block->has_track(track);
+       else
+               return false;
 }
 
 void TrainRouter::message(const Message &msg)
@@ -139,19 +120,27 @@ void TrainRouter::message(const Message &msg)
        }
        else if(msg.type=="clear-route")
                set_route(0);
-       else if(msg.type=="go-to-track")
-               go_to(*msg.value.value<Track *>());
-       else if(msg.type=="go-to-zone")
+       else if(msg.type=="set-destination-block")
+       {
+               if(msg.value.check_type<Block *>())
+                       set_destination(*msg.value.value<Block *>());
+               else
+                       set_destination(*msg.value.value<const Block *>());
+       }
+       else if(msg.type=="set-destination-zone")
        {
                if(msg.value.check_type<Zone *>())
-                       go_to(*msg.value.value<Zone *>());
+                       set_destination(*msg.value.value<Zone *>());
                else
-                       go_to(*msg.value.value<const Zone *>());
+                       set_destination(*msg.value.value<const Zone *>());
        }
 }
 
 void TrainRouter::tick(const Time::TimeStamp &, const Time::TimeDelta &)
 {
+       if(update_pending)
+               create_plans(train.get_layout());
+
        if(arriving && !train.get_speed())
        {
                train.set_active(false);
@@ -177,12 +166,16 @@ void TrainRouter::save(list<DataFile::Statement> &st) const
 void TrainRouter::block_reserved(Block &block, Train *t)
 {
        if(t!=&train)
+       {
+               if(!waits.empty() && waits.front().block==&block)
+               {
+                       train.stop_at(0);
+                       waits.pop_front();
+               }
                return;
-
-       yielding_to = 0;
+       }
 
        BlockIter b_iter(&block, t->get_entry_to_block(block));
-       BlockIter b_iter_next;
 
        RouteList::iterator route = routes.begin();
        if(advance_route(route, block))
@@ -196,7 +189,7 @@ void TrainRouter::block_reserved(Block &block, Train *t)
                }
 
                // Check if the next block is still part of the designated route
-               b_iter_next = b_iter.next(*route);
+               BlockIter b_iter_next = b_iter.next(*route);
 
                RouteList::iterator next_route = route;
                if(!advance_route(next_route, *b_iter_next))
@@ -205,61 +198,8 @@ void TrainRouter::block_reserved(Block &block, Train *t)
                        return;
                }
 
-       }
-       else
-               b_iter_next = b_iter.next();
-
-       // Check if there's another train and ask it to free the block if appropriate
-       if(b_iter_next)
-       {
-               if(Train *other_train = b_iter_next->get_train())
-               {
-                       /* There's another train ahead of us.  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. */
-                       int other_entry = other_train->get_entry_to_block(*b_iter_next);
-                       if(other_entry<0)
-                               throw logic_error("block reservation inconsistency");
-
-                       unsigned exit = b_iter_next.reverse().entry();
-                       unsigned other_exit = BlockIter(b_iter_next.block(), other_entry).reverse().entry();
-                       bool entry_conflict = (b_iter_next.entry()==other_exit);
-                       bool exit_conflict = (exit==static_cast<unsigned>(other_entry));
-                       // TODO: speed matching with preceding train
-
-                       TrainRouter *other_router = other_train->get_ai_of_type<TrainRouter>();
-                       int other_prio = (other_router ? other_router->get_priority() : 0);
-
-                       if(!entry_conflict && !exit_conflict && other_prio<priority)
-                       {
-                               /* Ask a lesser priority train going to the same direction to free
-                               the block for us */
-                               other_train->free_block(*b_iter_next);
-                       }
-                       else if(other_train!=yielding_to && (other_prio<priority || (other_prio==priority && entry_conflict)))
-                       {
-                               /* A lesser priority train is coming at us, we must ask it to free
-                               enough blocks to get clear of it to avoid a potential deadlock */
-                               BlockIter last_contested;
-                               RouteList::iterator j = route;
-                               for(BlockIter i=b_iter_next; (i && i->get_train()==other_train);)
-                               {
-                                       if(!advance_route(j, *i))
-                                               break;
-                                       last_contested = i;
-                                       i = i.next(*j);
-                               }
-
-                               if(last_contested)
-                               {
-                                       if(other_train->free_block(*last_contested))
-                                               other_router->yield_to(train);
-                                       else
-                                               yield_to(*other_train);
-                               }
-                       }
-               }
+               if(!waits.empty() && waits.front().block==b_iter_next.block())
+                       train.stop_at(&block);
        }
 }
 
@@ -339,6 +279,23 @@ bool TrainRouter::is_on_route(const Block &block)
        return advance_route(iter, block);
 }
 
+void TrainRouter::create_plans(Layout &layout)
+{
+       TrainRoutePlanner planner(layout);
+       planner.plan();
+
+       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>())
+                       router->update_pending = false;
+}
+
+
+TrainRouter::Wait::Wait():
+       block(0),
+       train(0)
+{ }
+
 
 TrainRouter::Loader::Loader(TrainRouter &r):
        DataFile::ObjectLoader<TrainRouter>(r)