*/
#include <msp/gl/meshbuilder.h>
-#include "libmarklin/locotype.h"
#include "catalogue.h"
#include "tracktype.h"
#include "vehicletype.h"
endpoint_mesh((GL::NORMAL3, GL::VERTEX3))
{
catalogue.signal_track_added.connect(sigc::mem_fun(this, &Catalogue3D::track_added));
- catalogue.signal_loco_added.connect(sigc::mem_fun(this, &Catalogue3D::loco_added));
+ catalogue.signal_vehicle_added.connect(sigc::mem_fun(this, &Catalogue3D::vehicle_added));
const map<unsigned, TrackType *> &trks = catalogue.get_tracks();
for(map<unsigned, TrackType *>::const_iterator i=trks.begin(); i!=trks.end(); ++i)
tracks[&track] = new TrackType3D(*this, track);
}
-void Catalogue3D::loco_added(const LocoType &loco)
+void Catalogue3D::vehicle_added(const VehicleType &veh)
{
- vehicles[&loco] = new VehicleType3D(*this, loco);
+ vehicles[&veh] = new VehicleType3D(*this, veh);
}
void Catalogue3D::build_endpoint_mesh()
const Msp::GL::Mesh &get_endpoint_mesh() const { return endpoint_mesh; }
private:
void track_added(const TrackType &);
- void loco_added(const LocoType &);
+ void vehicle_added(const VehicleType &);
void build_endpoint_mesh();
};
// Setup railroad control
DataFile::load(catalogue, "tracks.dat");
DataFile::load(catalogue, "locos.dat");
+ DataFile::load(catalogue, "wagons.dat");
DataFile::load(layout, options.layout_fn);
layout.signal_train_added.connect(sigc::mem_fun(this, &Engineer::train_added));
add(*(drp_type=new GLtk::Dropdown(res)));
drp_type->set_geometry(GLtk::Geometry(60, geom.h-50, geom.w-70, 20));
- const map<unsigned, LocoType *> &locos = engineer.get_catalogue().get_locomotives();
+ const map<unsigned, VehicleType *> &vehs = engineer.get_catalogue().get_vehicles();
unsigned n = 0;
- for(map<unsigned, LocoType *>::const_iterator i=locos.begin(); i!=locos.end(); ++i, ++n)
+ for(map<unsigned, VehicleType *>::const_iterator i=vehs.begin(); i!=vehs.end(); ++i, ++n)
{
+ if(!dynamic_cast<LocoType *>(i->second))
+ continue;
+
drp_type->append(format("%d %s", i->second->get_article_number(), i->second->get_name()));
if(train && i->second==&train->get_locomotive_type())
drp_type->set_selected_index(n);
{
if(!train)
{
- const map<unsigned, LocoType *> &locos = engineer.get_catalogue().get_locomotives();
- map<unsigned, LocoType *>::const_iterator i = locos.begin();
- advance(i, drp_type->get_selected_index());
+ const map<unsigned, VehicleType *> &vehs = engineer.get_catalogue().get_vehicles();
+ map<unsigned, VehicleType *>::const_iterator i = vehs.begin();
+ unsigned n = drp_type->get_selected_index();
+ while(!dynamic_cast<LocoType *>(i->second))
+ ++i;
+ while(n)
+ {
+ if(dynamic_cast<LocoType *>(i->second))
+ --n;
+ ++i;
+ }
unsigned addr = lexical_cast<unsigned>(ent_addr->get_text());
- train = new Train(engineer.get_layout(), *i->second, addr);
+ train = new Train(engineer.get_layout(), *dynamic_cast<LocoType *>(i->second), addr);
}
train->set_name(ent_name->get_text());
{
for(map<unsigned, TrackType *>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
delete i->second;
- for(map<unsigned, LocoType *>::iterator i=locos.begin(); i!=locos.end(); ++i)
+ for(map<unsigned, VehicleType *>::iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
delete i->second;
}
signal_track_added.emit(track);
}
-void Catalogue::add_locomotive(LocoType &loco)
-{
- if(locos.count(loco.get_article_number()))
- throw Exception("Duplicate track type");
-
- locos[loco.get_article_number()] = &loco;
- signal_loco_added.emit(loco);
-}
-
const TrackType &Catalogue::get_track(unsigned art_nr) const
{
map<unsigned, TrackType *>::const_iterator i=tracks.find(art_nr);
return *i->second;
}
-const LocoType &Catalogue::get_locomotive(unsigned art_nr) const
+void Catalogue::add_vehicle(VehicleType &veh)
{
- map<unsigned, LocoType *>::const_iterator i=locos.find(art_nr);
- if(i==locos.end())
- throw KeyError("Unknown locomotive type");
+ if(vehicles.count(veh.get_article_number()))
+ throw Exception("Duplicate vehicle type");
+
+ vehicles[veh.get_article_number()] = &veh;
+ signal_vehicle_added.emit(veh);
+}
+
+const VehicleType &Catalogue::get_vehicle(unsigned art_nr) const
+{
+ map<unsigned, VehicleType *>::const_iterator i = vehicles.find(art_nr);
+ if(i==vehicles.end())
+ throw KeyError("Unknown vehicle type");
return *i->second;
}
+const LocoType &Catalogue::get_locomotive(unsigned art_nr) const
+{
+ const VehicleType &veh = get_vehicle(art_nr);
+ if(const LocoType *loco = dynamic_cast<const LocoType *>(&veh))
+ return *loco;
+
+ throw Exception("Vehicle is not a locomotive");
+}
+
Catalogue::Loader::Loader(Catalogue &c):
DataFile::BasicLoader<Catalogue>(c)
add("rail_profile", &Loader::rail_profile);
add("scale", &Loader::scale);
add("track", &Loader::track);
+ add("vehicle", &Loader::vehicle);
}
void Catalogue::Loader::ballast_profile()
{
RefPtr<LocoType> loco = new LocoType(art_nr);
load_sub(*loco);
- obj.add_locomotive(*loco);
+ obj.add_vehicle(*loco);
loco.release();
}
trk.release();
}
+void Catalogue::Loader::vehicle(unsigned art_nr)
+{
+ RefPtr<VehicleType> veh = new VehicleType(art_nr);
+ load_sub(*veh);
+ obj.add_vehicle(*veh);
+ veh.release();
+}
+
} // namespace Marklin
void rail_profile();
void scale(float, float);
void track(unsigned);
+ void vehicle(unsigned);
};
sigc::signal<void, const TrackType &> signal_track_added;
- sigc::signal<void, const LocoType &> signal_loco_added;
+ sigc::signal<void, const VehicleType &> signal_vehicle_added;
private:
float scale;
Profile ballast_profile;
Profile path_profile;
std::map<unsigned, TrackType *> tracks;
- std::map<unsigned, LocoType *> locos;
+ std::map<unsigned, VehicleType *> vehicles;
Layout layout;
public:
const TrackType &get_track(unsigned) const;
const std::map<unsigned, TrackType *> &get_tracks() const { return tracks; }
- void add_locomotive(LocoType &);
+ void add_vehicle(VehicleType &);
+ const VehicleType &get_vehicle(unsigned) const;
const LocoType &get_locomotive(unsigned) const;
- const std::map<unsigned, LocoType *> &get_locomotives() const { return locos; }
+ const std::map<unsigned, VehicleType *> &get_vehicles() const { return vehicles; }
Layout &get_layout() { return layout; }
};
#ifndef LIBMARKLIN_GEOMETRY_H_
#define LIBMARKLIN_GEOMETRY_H_
+#include <cmath>
#include <vector>
namespace Marklin {
Point(float x_, float y_, float z_): x(x_), y(y_), z(z_) { }
};
+inline float distance(const Point &p, const Point &q)
+{ return sqrt((p.x-q.x)*(p.x-q.x) + (p.y-q.y)*(p.y-q.y) + (p.z-q.z)*(p.z-q.z)); }
+
struct TrackPoint
{
Point pos;
if(!active)
set_active(true);
- Track *track = vehicles[0]->get_track();
+ Vehicle &vehicle = *(reverse ? vehicles.back() : vehicles.front());
+ Track *track = vehicle.get_track();
bool ok = false;
for(list<BlockRef>::const_iterator i=cur_blocks.begin(); (!ok && i!=cur_blocks.end()); ++i)
if(ok)
{
float d = get_real_speed(current_speed)*(dt/Time::sec);
- vehicles[0]->advance(reverse ? -d : d);
+ vehicle.advance(reverse ? -d : d);
}
}
else if(end_of_route)
add("real_speed", &Loader::real_speed);
add("route", &Loader::route);
add("timetable", &Loader::timetable);
+ add("vehicle", &Loader::vehicle);
}
void Train::Loader::block(unsigned id)
load_sub(*obj.timetable);
}
+void Train::Loader::vehicle(unsigned n)
+{
+ const VehicleType &vtype = obj.layout.get_catalogue().get_vehicle(n);
+ Vehicle *veh = new Vehicle(obj.layout, vtype);
+ obj.vehicles.back()->attach_back(*veh);
+ obj.vehicles.push_back(veh);
+}
+
} // namespace Marklin
void real_speed(unsigned, float, float);
void route(const std::string &);
void timetable();
+ void vehicle(unsigned);
};
sigc::signal<void, const std::string &> signal_name_changed;
#include "vehicletype.h"
using namespace std;
+using namespace Msp;
namespace Marklin {
layout.remove_vehicle(*this);
}
+void Vehicle::attach_back(Vehicle &veh)
+{
+ if(next || veh.prev)
+ throw InvalidState("Already attached");
+
+ next = &veh;
+ veh.prev = this;
+}
+
+void Vehicle::attach_front(Vehicle &veh)
+{
+ if(prev || veh.next)
+ throw InvalidState("Already attached");
+
+ next = &veh;
+ veh.prev = this;
+}
+
+void Vehicle::detach_back()
+{
+ if(!next)
+ throw InvalidState("Not attached");
+
+ next->prev = 0;
+ next = 0;
+}
+
+void Vehicle::detach_front()
+{
+ if(!prev)
+ throw InvalidState("Not attached");
+
+ prev->next = 0;
+ prev = 0;
+}
+
void Vehicle::place(Track *t, unsigned e, float o, PlaceMode m)
{
track_pos = TrackPosition(t, e, o);
track_pos.advance(type.get_length()/2);
update_position();
+ propagate_position();
}
void Vehicle::advance(float d)
{
track_pos.advance(d);
update_position();
+ propagate_position();
}
void Vehicle::update_position()
const vector<VehicleType::Axle> &axles = type.get_axles();
if(axles.size()>=2)
- tp = get_position(axles.front().position, axles.back().position, track_pos);
+ {
+ float wheelbase = axles.front().position-axles.back().position;
+ tp = get_point(track_pos, wheelbase, -axles.back().position/wheelbase);
+ }
else
{
const vector<VehicleType::Bogie> &bogies = type.get_bogies();
if(bogies.size()>=2)
- // XXX Calculate bogie positions correctly
- tp = get_position(bogies.front().position, bogies.back().position, track_pos);
+ {
+ TrackPosition front = track_pos;
+ front.advance(bogies.front().position);
+ TrackPosition back = track_pos;
+ back.advance(bogies.back().position);
+ float bogie_spacing = bogies.front().position-bogies.back().position;
+ adjust_for_distance(front, back, bogie_spacing);
+
+ const vector<VehicleType::Axle> &front_axles = bogies.front().axles;
+ float wheelbase = front_axles.front().position-front_axles.back().position;
+ Point front_point = get_point(front, wheelbase, -front_axles.back().position/wheelbase).pos;
+
+ const vector<VehicleType::Axle> &back_axles = bogies.back().axles;
+ wheelbase = back_axles.front().position-back_axles.back().position;
+ Point back_point = get_point(back, wheelbase, -back_axles.back().position/wheelbase).pos;
+
+ tp = get_point(front_point, back_point, -bogies.back().position/bogie_spacing);
+ }
else
tp = track_pos.get_point();
}
+
position = tp.pos;
direction = tp.dir;
}
-TrackPoint Vehicle::get_position(float front, float back, const TrackPosition &tpos)
+void Vehicle::update_position_from(const Vehicle &veh)
{
- TrackPosition front_pos = tpos;
- front_pos.advance(front);
+ int sign = (&veh==prev ? -1 : 1);
- TrackPosition back_pos = tpos;
- back_pos.advance(back);
+ float tdist = (type.get_length()+veh.type.get_length())/2;
+ float margin = layout.get_catalogue().get_scale();
- float target_dist = front-back;
+ float dist = distance(veh.position, position);
+ if(dist<tdist-margin || dist>tdist+margin)
+ {
+ track_pos = veh.track_pos;
+ track_pos.advance(sign*tdist);
+ update_position();
+
+ dist = distance(veh.position, position);
+ }
+
+ track_pos.advance(sign*(tdist-dist));
+ update_position();
+}
+void Vehicle::propagate_position()
+{
+ if(prev)
+ propagate_forward();
+ if(next)
+ propagate_backward();
+}
+
+void Vehicle::propagate_forward()
+{
+ prev->update_position_from(*this);
+
+ if(prev->prev)
+ prev->propagate_forward();
+}
+
+void Vehicle::propagate_backward()
+{
+ next->update_position_from(*this);
+
+ if(next->next)
+ next->propagate_backward();
+}
+
+void Vehicle::adjust_for_distance(TrackPosition &front, TrackPosition &back, float tdist, float ratio) const
+{
+ float margin = 0.01*layout.get_catalogue().get_scale();
+ int adjust_dir = 0;
while(1)
{
- Point front_point = front_pos.get_point().pos;
- Point back_point = back_pos.get_point().pos;
+ Point front_point = front.get_point().pos;
+ Point back_point = back.get_point().pos;
float dx = front_point.x-back_point.x;
float dy = front_point.y-back_point.y;
float dz = front_point.z-back_point.z;
float dist = sqrt(dx*dx+dy*dy+dz*dz);
- if(dist<target_dist)
+ float diff = tdist-dist;
+ if(diff<-margin && adjust_dir<=0)
{
- float adjust = target_dist-dist+0.01*layout.get_catalogue().get_scale();
- front_pos.advance(adjust/2);
- back_pos.advance(-adjust/2);
+ diff -= margin;
+ adjust_dir = -1;
}
- else
+ else if(diff>margin && adjust_dir>=0)
{
- float f = -back/target_dist;
- TrackPoint pt;
- pt.pos = Point(back_point.x+dx*f, back_point.y+dy*f, back_point.z+dz*f);
- pt.dir = atan2(dy, dx);
- return pt;
+ diff += margin;
+ adjust_dir = 1;
}
+ else
+ return;
+
+ front.advance(diff*(1-ratio));
+ back.advance(-diff*ratio);
}
}
+TrackPoint Vehicle::get_point(const Point &front, const Point &back, float ratio) const
+{
+ float dx = front.x-back.x;
+ float dy = front.y-back.y;
+ float dz = front.z-back.z;
+
+ TrackPoint tp;
+ tp.pos = Point(back.x+dx*ratio, back.y+dy*ratio, back.z+dz*ratio);
+ tp.dir = atan2(dy, dx);
+
+ return tp;
+}
+
+TrackPoint Vehicle::get_point(const TrackPosition &pos, float tdist, float ratio) const
+{
+ TrackPosition front = pos;
+ front.advance(tdist*(1-ratio));
+
+ TrackPosition back = pos;
+ back.advance(-tdist*ratio);
+
+ adjust_for_distance(front, back, tdist, ratio);
+ return get_point(front.get_point().pos, back.get_point().pos, ratio);
+}
+
Vehicle::TrackPosition::TrackPosition():
track(0),
const VehicleType &get_type() const { return type; }
+ void attach_back(Vehicle &);
+ void attach_front(Vehicle &);
+ void detach_back();
+ void detach_front();
+ Vehicle *get_next() const { return next; }
+ Vehicle *get_previous() const { return prev; }
+
void place(Track *, unsigned, float, PlaceMode = CENTER);
void advance(float);
Track *get_track() const { return track_pos.track; }
float get_direction() const { return direction; }
private:
void update_position();
- TrackPoint get_position(float, float, const TrackPosition &);
+ void update_position_from(const Vehicle &);
+ void propagate_position();
+ void propagate_forward();
+ void propagate_backward();
+
+ void adjust_for_distance(TrackPosition &, TrackPosition &, float, float = 0.5) const;
+ TrackPoint get_point(const Point &, const Point &, float = 0.5) const;
+ TrackPoint get_point(const TrackPosition &, float, float = 0.5) const;
};
} // namespace Marklin
public:
VehicleType(unsigned);
+ virtual ~VehicleType() { } // XXX temporary
unsigned get_article_number() const { return art_nr; }
const std::string &get_name() const { return name; }
--- /dev/null
+/* $Id$ */
+
+scale 1 87;
+gauge 16.5;
+
+vehicle 46274
+{
+ name "Saar Railroad Gmhs 54";
+
+ length 101;
+ width 33;
+ height 33;
+
+ axle { position 31; wheel_diameter 10; };
+ axle { position -31; wheel_diameter 10; };
+};
+
+vehicle 100001
+{
+ name "BR 50 tender";
+
+ length 90;
+ width 33;
+ height 33;
+
+ bogie
+ {
+ position 23;
+ axle { position 11; wheel_diameter 10; };
+ axle { position -11; wheel_diameter 10; };
+ };
+ bogie
+ {
+ position -21;
+ axle { position 11; wheel_diameter 10; };
+ axle { position -11; wheel_diameter 10; };
+ };
+};