priority(0),
yielding_to(0),
cur_blocks_end(blocks.end()),
+ clear_blocks_end(blocks.end()),
pending_block(0),
reserving(false),
advancing(false),
layout.signal_block_reserved.connect(sigc::mem_fun(this, &Train::block_reserved));
layout.get_driver().signal_sensor.connect(sigc::mem_fun(this, &Train::sensor_event));
- layout.get_driver().signal_turnout.connect(sigc::mem_fun(this, &Train::turnout_event));
layout.get_driver().signal_halt.connect(sigc::mem_fun(this, &Train::halt_event));
+ const set<Track *> &tracks = layout.get_tracks();
+ for(set<Track *>::const_iterator i=tracks.begin(); i!=tracks.end(); ++i)
+ if((*i)->get_turnout_id())
+ (*i)->signal_path_changed.connect(sigc::hide(sigc::bind(sigc::mem_fun(this, &Train::turnout_path_changed), sigc::ref(**i))));
+
controller->signal_control_changed.connect(sigc::mem_fun(this, &Train::control_changed));
}
}
}
-void Train::turnout_event(unsigned addr, bool)
+void Train::turnout_path_changed(Track &track)
{
- if(pending_block && (!pending_block->get_train() || pending_block->get_train()==this))
- {
- unsigned pending_addr = pending_block->get_turnout_id();
- bool double_addr = (*pending_block->get_tracks().begin())->get_type().is_double_address();
- if(addr==pending_addr || (double_addr && addr==pending_addr+1))
+ for(list<BlockIter>::iterator i=blocks.begin(); i!=blocks.end(); ++i)
+ if((*i)->get_turnout_id()==track.get_turnout_id())
{
- if(reserving)
- pending_block = 0;
- else
- reserve_more();
+ if(!reserving)
+ check_turnout_paths(false);
+ else if(i==clear_blocks_end)
+ ++clear_blocks_end;
}
- }
}
void Train::halt_event(bool h)
float min_dist = controller->get_braking_distance()*1.3+approach_margin*2;
BlockIter block = start;
- BlockIter good = start;
+ list<BlockIter>::iterator good_end = blocks.end();
Track *divert_track = 0;
bool try_divert = false;
unsigned good_sens = nsens;
// Keep the blocks if we arrived at the end of the route
if(!blocking_train)
{
- good = last;
+ good_end = blocks.end();
good_sens = nsens;
good_dist = dist;
end_of_route = true;
{
if(!blocking_train)
{
- good = last;
+ good_end = blocks.end();
good_sens = nsens;
good_dist = dist;
}
{
/* The other train is not coming to the blocks we're holding, so we
can keep them. */
- good = last;
+ good_end = blocks.end();
good_sens = nsens;
good_dist = dist;
}
points or if there was no turnout immediately before this one.
With multiple successive turnouts (as is common in crossovers) it's
best to hold at one we can divert from. */
- good = last;
+ good_end = blocks.end();
good_sens = nsens;
good_dist = dist;
}
- // 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(block->get_turnout_id());
- if(path<0)
- 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<<i))
- path = i;
- }
-
- if(path!=static_cast<int>(track->get_active_path()))
- {
- // The turnout is set to wrong path - switch and wait for it
- pending_block = &*block;
- track->set_active_path(path);
- if(pending_block)
- {
- block->reserve(0);
- break;
- }
- }
-
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 */
contested_blocks.pop_front();
blocks.push_back(block);
+
if(cur_blocks_end==blocks.end())
--cur_blocks_end;
+ if(clear_blocks_end==blocks.end())
+ --clear_blocks_end;
+ if(good_end==blocks.end())
+ --good_end;
+
if(block->get_sensor_id())
++nsens;
if(nsens>0)
}
// Unreserve blocks that were not good
- while(blocks.end()!=cur_blocks_end && blocks.back()!=good)
- {
- if(--blocks.end()==cur_blocks_end)
- cur_blocks_end = blocks.end();
- blocks.back()->reserve(0);
- blocks.pop_back();
- }
+ release_blocks(good_end, blocks.end());
- if(!blocks.back()!=start)
+ if(blocks.back()!=start)
// We got some new blocks, so no longer need to yield
yielding_to = 0;
+ check_turnout_paths(true);
+
// Make any sensorless blocks at the beginning immediately current
while(cur_blocks_end!=blocks.end() && !(*cur_blocks_end)->get_sensor_id())
++cur_blocks_end;
return good_sens;
}
+void Train::check_turnout_paths(bool set)
+{
+ if(clear_blocks_end==blocks.end())
+ return;
+
+ list<RouteRef>::iterator route = routes.begin();
+
+ for(list<BlockIter>::iterator i=clear_blocks_end; i!=blocks.end(); ++i)
+ {
+ advance_route(route, *i->track_iter());
+
+ if((*i)->get_turnout_id())
+ {
+ TrackIter track = i->track_iter();
+ const TrackType::Endpoint &track_ep = track->get_type().get_endpoints()[track.entry()];
+
+ int path = -1;
+ for(list<RouteRef>::iterator j=route; (path<0 && j!=routes.end()); ++j)
+ path = j->route->get_turnout((*i)->get_turnout_id());
+ if(path<0)
+ path = track->get_active_path();
+ if(!(track_ep.paths&(1<<path)))
+ {
+ list<BlockIter>::iterator j = i;
+ if(++j!=blocks.end())
+ {
+ TrackIter rev = j->track_iter().flip();
+ unsigned mask = rev->get_type().get_endpoints()[rev.entry()].paths&track_ep.paths;
+ for(path=0; mask>1; mask>>=1, ++path) ;
+ }
+ else
+ return;
+ }
+
+ if(path!=static_cast<int>(track->get_active_path()))
+ {
+ if(set)
+ track->set_active_path(path);
+
+ continue;
+ }
+ }
+
+ if(i==clear_blocks_end)
+ ++clear_blocks_end;
+ }
+}
+
float Train::get_reserved_distance_until(const Block *until_block, bool back) const
{
if(blocks.empty())
return 0;
BlockList::const_iterator block = blocks.begin();
- while(block!=blocks.end() && !(*block)->has_track(*track))
+ while(block!=clear_blocks_end && !(*block)->has_track(*track))
++block;
- if(block==blocks.end() || &**block==until_block)
+ if(block==clear_blocks_end || &**block==until_block)
return 0;
float result = veh.get_offset();
else
{
++block;
- if(block==blocks.end())
+ if(block==clear_blocks_end)
break;
}
{
if(begin==cur_blocks_end)
cur_blocks_end = end;
+ if(begin==clear_blocks_end)
+ clear_blocks_end = end;
Block &block = **begin;
blocks.erase(begin++);