#include <msp/time/units.h>
#include <msp/time/utils.h>
#include "aicontrol.h"
+#include "beamgate.h"
#include "block.h"
#include "catalogue.h"
#include "driver.h"
layout.add_train(*this);
- layout.get_driver().add_loco(address, protocol, loco_type);
+ loco_id = layout.get_driver().add_loco(address, protocol, loco_type);
layout.get_driver().signal_loco_speed.connect(sigc::mem_fun(this, &Train::loco_speed_event));
layout.get_driver().signal_loco_function.connect(sigc::mem_fun(this, &Train::loco_func_event));
{
if(!loco_type.get_functions().count(func))
throw invalid_argument("Train::set_function");
- layout.get_driver().set_loco_function(address, func, state);
+ layout.get_driver().set_loco_function(loco_id, func, state);
}
float Train::get_control(const string &ctrl) const
return controller->get_speed();
}
+float Train::get_maximum_speed() const
+{
+ float ms = 0;
+ for(vector<Vehicle *>::const_iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
+ {
+ float vms = (*i)->get_type().get_maximum_speed();
+ if(ms<=0 || (vms>0 && vms<ms))
+ ms = vms;
+ }
+ return ms;
+}
+
bool Train::get_function(unsigned func) const
{
return (functions>>func)&1;
(*i)->message(msg);
}
-void Train::place(const BlockIter &block)
+bool Train::place(const BlockIter &block)
{
if(!block)
throw invalid_argument("Train::place");
if(controller->get_speed())
throw logic_error("moving");
- allocator.start_from(block);
accurate_position = false;
+ last_entry_block = BlockIter();
- if(reverse)
- vehicles.front()->place(block.reverse().track_iter(), 0, Vehicle::FRONT_BUFFER);
+ if(allocator.start_from(block))
+ {
+ if(reverse)
+ vehicles.front()->place(block.reverse().track_iter(), VehiclePlacement::FRONT_BUFFER);
+ else
+ vehicles.back()->place(block.track_iter(), VehiclePlacement::BACK_BUFFER);
+ return true;
+ }
else
- vehicles.back()->place(block.track_iter(), 0, Vehicle::BACK_BUFFER);
+ {
+ unplace();
+ return false;
+ }
}
void Train::unplace()
allocator.clear();
accurate_position = false;
+ last_entry_block = BlockIter();
for(vector<Vehicle *>::iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
(*i)->unplace();
bool Train::is_block_critical(const Block &block) const
{
- return get_reserved_distance_until(&block)<controller->get_braking_distance()*1.3;
+ return get_reserved_distance_until(&block)<=controller->get_braking_distance()*1.3;
}
BlockIter Train::get_first_noncritical_block() const
dist += i->get_path_length(i.entry());
- if(i->get_sensor_id())
+ if(i->get_sensor_address())
sensor_seen = true;
}
bool r = reverse;
if(loco_type.get_swap_direction())
r = !r;
- driver.set_loco_reverse(address, r);
+ driver.set_loco_reverse(loco_id, r);
allocator.reverse();
+ last_entry_block = BlockIter();
}
if(speed_quantizer)
if(speed_step!=current_speed_step && !speed_changing && !driver.is_halted() && driver.get_power())
{
speed_changing = true;
- driver.set_loco_speed(address, speed_step);
+ driver.set_loco_speed(loco_id, speed_step);
pure_speed = false;
}
Vehicle &vehicle = *(reverse ? vehicles.back() : vehicles.front());
float d = speed*(dt/Time::sec);
- if(allocator.is_block_current(vehicle.get_track()->get_block()))
+ if(allocator.is_block_current(vehicle.get_placement().get_position(reverse ? VehiclePlacement::BACK_AXLE : VehiclePlacement::FRONT_AXLE)->get_block()))
{
SetFlag setf(advancing);
vehicle.advance(reverse ? -d : d);
signal_control_changed.emit(ctrl.name, ctrl.value);
}
-void Train::loco_speed_event(unsigned addr, unsigned speed, bool rev)
+void Train::loco_speed_event(unsigned id, unsigned speed, bool rev)
{
- if(addr==address)
+ if(id==loco_id)
{
current_speed_step = speed;
bool r = reverse;
if(loco_type.get_swap_direction())
r = !r;
if(rev!=r)
- layout.get_driver().set_loco_reverse(address, r);
+ layout.get_driver().set_loco_reverse(loco_id, r);
speed_changing = false;
pure_speed = false;
}
}
-void Train::loco_func_event(unsigned addr, unsigned func, bool state)
+void Train::loco_func_event(unsigned id, unsigned func, bool state)
{
- if(addr==address)
+ if(id==loco_id)
{
if(state)
functions |= 1<<func;
void Train::sensor_state_changed(Sensor &sensor, Sensor::State state)
{
- if(state!=Sensor::MAYBE_ACTIVE)
+ if(!current_speed_step || state!=Sensor::MAYBE_ACTIVE)
return;
Block *block = sensor.get_block();
if(!block || block->get_train()!=this)
return;
+ if(last_entry_block && &*last_entry_block!=block)
+ {
+ for(BlockIter i=last_entry_block.next(); (i && &*i!=block); i=i.next())
+ if(i->get_train()!=this || i->get_sensor_address())
+ return;
+ }
+
if(dynamic_cast<TrackCircuit *>(&sensor))
{
- if(last_entry_block)
+ if(last_entry_block && pure_speed && speed_quantizer)
{
- float travel_distance = -1;
- if(pure_speed && speed_quantizer && current_speed_step>0)
- travel_distance = 0;
+ float travel_distance = 0;
for(BlockIter i=last_entry_block; &*i!=block; i=i.next())
- {
- if(i->get_sensor_id())
- return;
- if(travel_distance>=0)
- travel_distance += i->get_path_length(i.entry());
- }
+ travel_distance += i->get_path_length(i.entry());
if(travel_distance>0)
{
accurate_position = true;
overshoot_dist = 0;
- if(!advancing && vehicles.front()->get_track())
+ if(!advancing && vehicles.front()->is_placed())
{
TrackIter track = last_entry_block.track_iter();
if(reverse)
{
track = track.flip();
- vehicles.back()->place(track, 0, Vehicle::BACK_AXLE);
+ vehicles.back()->place(track, VehiclePlacement::BACK_AXLE);
}
else
- vehicles.front()->place(track, 0, Vehicle::FRONT_AXLE);
+ vehicles.front()->place(track, VehiclePlacement::FRONT_AXLE);
+ }
+ }
+ else if(BeamGate *gate = dynamic_cast<BeamGate *>(&sensor))
+ {
+ if(!advancing && vehicles.front()->is_placed())
+ {
+ TrackIter track = allocator.iter_for(*block).track_iter();
+ for(; (track && &track->get_block()==block); track=track.next())
+ if(track.track()==gate->get_track())
+ {
+ if(reverse)
+ track = track.reverse();
+ float offset = gate->get_offset_from_endpoint(track.entry());
+ if(reverse)
+ vehicles.back()->place(TrackOffsetIter(track, offset), VehiclePlacement::BACK_BUFFER);
+ else
+ vehicles.front()->place(TrackOffsetIter(track, offset), VehiclePlacement::FRONT_BUFFER);
+ break;
+ }
}
}
}
Vehicle &veh = *(reverse ? vehicles.back() : vehicles.front());
- TrackIter track = veh.get_track_iter();
+ TrackOffsetIter track = veh.get_placement().get_position(reverse ? VehiclePlacement::BACK_AXLE : VehiclePlacement::FRONT_AXLE);
if(!track) // XXX Probably unnecessary
return 0;
return 0;
// Account for the vehicle's offset on its current track
- float result = veh.get_offset();
+ float result = track.offset();
if(reverse)
track = track.reverse();
else
- result = track->get_type().get_path_length(track->get_active_path())-result;
+ result = track->get_path_length()-result;
result -= veh.get_type().get_length()/2;
BlockIter block = track.block_iter();
// Count remaining distance in the vehicle's current block
for(track=track.next(); &track->get_block()==&*block; track=track.next())
- result += track->get_type().get_path_length(track->get_active_path());
+ result += track->get_path_length();
const BlockIter &last = allocator.last();
if(&*block==&*last)
{
TrackIter track = obj.allocator.first().track_iter();
float offset = 2*obj.layout.get_catalogue().get_scale();
- obj.vehicles.back()->place(track, offset, Vehicle::BACK_BUFFER);
+ obj.vehicles.back()->place(TrackOffsetIter(track, offset), VehiclePlacement::BACK_BUFFER);
}
}
void Train::Loader::vehicle(ArticleNumber art_nr)
{
- const VehicleType &vtype = obj.layout.get_catalogue().get_vehicle(art_nr);
+ const VehicleType &vtype = obj.layout.get_catalogue().get<VehicleType>(art_nr);
Vehicle *veh = new Vehicle(obj.layout, vtype);
obj.vehicles.back()->attach_back(*veh);
obj.vehicles.push_back(veh);