bool Train::free_block(Block &block)
{
+ float margin = 10*layout.get_catalogue().get_scale();
+ if(get_reserved_distance_until(&block, false)<controller->get_braking_distance()*1.3+margin)
+ return false;
+
unsigned nsens = 0;
for(list<BlockRef>::iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
{
float Train::get_reserved_distance() const
{
- if(cur_blocks.empty())
- return 0;
-
- Vehicle &veh = *(reverse ? vehicles.back() : vehicles.front());
- const VehicleType &vtype = veh.get_type();
-
- Track *track = veh.get_track();
- if(!track)
- return 0;
- unsigned entry = veh.get_entry();
-
- float result = -vtype.get_length()/2;
- if(reverse)
- {
- entry = track->traverse(entry);
- result += veh.get_offset();
- }
- else
- result -= veh.get_offset();
-
- bool first = true;
- list<BlockRef>::const_iterator block = cur_blocks.begin();
- while(1)
- {
- if(!first || !reverse)
- result += track->get_type().get_path_length(track->get_active_path());
- first = false;
-
- if(track->get_type().get_endpoints().size()<2)
- return result;
-
- unsigned exit = track->traverse(entry);
- Track *next = track->get_link(exit);
-
- while(!block->block->get_tracks().count(next))
- {
- ++block;
- if(block==cur_blocks.end())
- block = rsv_blocks.begin();
- if(block==rsv_blocks.end())
- return result;
- }
-
- entry = next->get_endpoint_by_link(*track);
- track = next;
- }
+ return get_reserved_distance_until(0, false);
}
void Train::tick(const Time::TimeStamp &t, const Time::TimeDelta &dt)
if(!cur_blocks.empty() && !cur_blocks.front().block->get_sensor_id())
{
- Vehicle &veh = *(reverse ? vehicles.front() : vehicles.back());
-
- list<BlockRef>::iterator i = cur_blocks.begin();
- const Block::Endpoint &bep = i->block->get_endpoints()[i->entry];
-
- Track *track = bep.track;
- unsigned entry = bep.track_ep;
-
- bool found = false;
- float dist = veh.get_offset();
- if(reverse)
- dist = veh.get_track()->get_type().get_path_length(veh.get_track()->get_active_path())-dist;
- dist -= veh.get_type().get_length()/2;
- while(1)
- {
- if(track==veh.get_track())
- {
- found = true;
- break;
- }
-
- if(i!=cur_blocks.begin())
- {
- float path_len = track->get_type().get_path_length(track->get_active_path());
- dist += path_len;
- }
-
- unsigned exit = track->traverse(entry);
- Track *next = track->get_link(exit);
- entry = next->get_endpoint_by_link(*track);
- track = next;
-
- if(!i->block->get_tracks().count(track))
- {
- ++i;
- if(i==cur_blocks.end())
- break;
- }
- }
+ float dist = get_reserved_distance_until(cur_blocks.front().block, true);
- if(found && i!=cur_blocks.begin() && dist>10*layout.get_catalogue().get_scale())
+ if(dist>10*layout.get_catalogue().get_scale())
{
cur_blocks.front().block->reserve(0);
cur_blocks.erase(cur_blocks.begin());
pending_block = 0;
- // See how many sensor blocks we already have
+ // See how many sensor blocks and how much track we already have
unsigned nsens = 0;
+ float dist = 0;
for(list<BlockRef>::const_iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
+ {
if(i->block->get_sensor_id())
++nsens;
+ if(nsens>0)
+ {
+ float length = 0;
+ i->block->traverse(i->entry, &length);
+ dist += length;
+ }
+ }
if(end_of_route)
return nsens;
}
}
- SetFlag setf(reserving);
+ 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;
unsigned good_sens = nsens;
+ float good_dist = dist;
Train *blocking_train = 0;
std::list<BlockRef> contested_blocks;
- while(good_sens<3 || !contested_blocks.empty())
+
+ SetFlag setf(reserving);
+
+ while(good_sens<3 || good_dist<min_dist || !contested_blocks.empty())
{
// Traverse to the next block
- unsigned exit = last->block->traverse(last->entry, cur_route);
+ float length = 0;
+ unsigned exit = last->block->traverse(last->entry, cur_route, &length);
Block *link = last->block->get_link(exit);
if(!link)
break;
{
good = last;
good_sens = nsens;
+ good_dist = dist;
end_of_route = true;
}
break;
{
good = last;
good_sens = nsens;
+ good_dist = dist;
}
break;
}
other train to pass */
good = last;
good_sens = nsens;
+ good_dist = dist;
// Ask a lesser priority train to free the block for us
if(other_train->get_priority()<priority)
// Keep the blocks reserved so far, as either us or the other train can diverge
good = last;
good_sens = nsens;
+ good_dist = dist;
// Figure out what path we'd like to take on the turnout
int path = -1;
last = &rsv_blocks.back();
if(last->block->get_sensor_id())
++nsens;
+ if(nsens>0)
+ dist += length;
}
// Unreserve blocks that were not good
return good_sens;
}
+float Train::get_reserved_distance_until(const Block *until_block, bool back) const
+{
+ if(cur_blocks.empty())
+ return 0;
+
+ Vehicle &veh = *(reverse!=back ? vehicles.back() : vehicles.front());
+ const VehicleType &vtype = veh.get_type();
+
+ Track *track = veh.get_track();
+ if(!track)
+ return 0;
+
+ list<BlockRef>::const_iterator block = cur_blocks.begin();
+ while(block!=cur_blocks.end() && !block->block->get_tracks().count(track))
+ ++block;
+ if(block==cur_blocks.end() || block->block==until_block)
+ return 0;
+
+ unsigned entry = veh.get_entry();
+
+ float result = veh.get_offset();
+ if(reverse!=back)
+ entry = track->traverse(entry);
+ 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)
+ break;
+
+ Track *next = track->get_link(track->traverse(entry));
+
+ if(!block->block->get_tracks().count(next))
+ {
+ if(back)
+ {
+ if(block==cur_blocks.begin())
+ break;
+ --block;
+ }
+ else
+ {
+ ++block;
+ if(block==cur_blocks.end())
+ block = rsv_blocks.begin();
+ if(block==rsv_blocks.end())
+ break;
+ }
+
+ if(block->block==until_block)
+ break;
+ }
+
+ entry = next->get_endpoint_by_link(*track);
+ track = next;
+
+ result += track->get_type().get_path_length(track->get_active_path());
+ }
+
+ return result;
+}
+
float Train::get_real_speed(unsigned i) const
{
if(real_speed[i].weight)