#include <msp/strings/format.h>
#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"
#include "layout.h"
-#include "route.h"
#include "simplecontroller.h"
#include "speedquantizer.h"
+#include "timetable.h"
#include "trackcircuit.h"
#include "trackiter.h"
#include "tracktype.h"
#include "trainrouter.h"
#include "vehicle.h"
#include "vehicletype.h"
-#include "zone.h"
using namespace std;
using namespace Msp;
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));
- layout.signal_sensor_state_changed.connect(sigc::mem_fun(this, &Train::sensor_state_changed));
-
layout.get_driver().signal_halt.connect(sigc::mem_fun(this, &Train::halt_event));
controller->signal_control_changed.connect(sigc::mem_fun(this, &Train::control_changed));
+
+ allocator.signal_advanced.connect(sigc::mem_fun(this, &Train::advanced));
+ allocator.signal_rear_advanced.connect(signal_rear_advanced);
}
Train::~Train()
{
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()))
+ Block &block = vehicle.get_placement().get_position(reverse ? VehiclePlacement::BACK_AXLE : VehiclePlacement::FRONT_AXLE)->get_block();
+ if(allocator.is_block_current(block))
{
SetFlag setf(advancing);
vehicle.advance(reverse ? -d : d);
overshoot_dist += d;
if(overshoot_dist>40*layout.get_catalogue().get_scale())
{
- layout.emergency(name+" has not arrived at sensor");
+ layout.emergency(&block, name+" has not arrived at sensor");
accurate_position = false;
}
}
{
st.push_back((DataFile::Statement("name"), name));
+ const Catalogue &cat = layout.get_catalogue();
for(vector<Vehicle *>::const_iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
if(i!=vehicles.begin())
- st.push_back((DataFile::Statement("vehicle"), (*i)->get_type().get_article_number()));
+ st.push_back((DataFile::Statement("vehicle"), cat.get_name(&(*i)->get_type())));
if(speed_quantizer)
{
router->save(ss.sub);
st.push_back(ss);
}
+ else if(Timetable *timetable = dynamic_cast<Timetable *>(*i))
+ {
+ DataFile::Statement ss("timetable");
+ timetable->save(ss.sub);
+ st.push_back(ss);
+ }
}
}
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)
+void Train::advanced(Block &block, Sensor *sensor)
{
- Block *block = 0;
- if(TrackCircuit *tc = dynamic_cast<TrackCircuit *>(&sensor))
- block = &tc->get_block();
- else
+ if(!sensor || sensor==block.get_sensor())
+ signal_advanced.emit(block);
+
+ if(!sensor)
return;
- if(block->get_train()==this && state==Sensor::MAYBE_ACTIVE)
+ if(sensor==block.get_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());
- }
+ for(BlockIter i=last_entry_block; &*i!=█ i=i.next())
+ travel_distance += i->get_path_length(i.entry());
if(travel_distance>0)
{
}
}
- last_entry_block = allocator.iter_for(*block);
+ last_entry_block = allocator.iter_for(block);
travel_time = Time::zero;
- pure_speed = true;
- accurate_position = true;
+ if(!layout.get_driver().is_halted())
+ {
+ pure_speed = true;
+ 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)
add("name", &Loader::name);
add("quantized_speed", &Loader::quantized_speed);
add("router", &Loader::router);
+ add("timetable", &Loader::timetable);
add("vehicle", &Loader::vehicle);
}
{
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);
}
}
load_sub(*rtr);
}
-void Train::Loader::vehicle(ArticleNumber art_nr)
+void Train::Loader::timetable()
+{
+ Timetable *ttbl = new Timetable(obj);
+ load_sub(*ttbl, obj.layout);
+}
+
+void Train::Loader::vehicle(const string &n)
{
- const VehicleType &vtype = obj.layout.get_catalogue().get_vehicle(art_nr);
+ const VehicleType &vtype = obj.layout.get_catalogue().get<VehicleType>(n);
Vehicle *veh = new Vehicle(obj.layout, vtype);
obj.vehicles.back()->attach_back(*veh);
obj.vehicles.push_back(veh);