function 2 "telex";
function 3 "sfx";
function 5 "whst";
+
+ length 150;
+ width 33;
+ height 33;
+
+ bogie
+ {
+ position 39;
+ axle { position 23; wheel_diameter 9; };
+ };
+ axle { position 31; wheel_diameter 16; powered true; };
+ axle { position 11; wheel_diameter 16; powered true; };
+ axle { position -9; wheel_diameter 16; powered true; };
+ axle { position -29; wheel_diameter 16; powered true; };
+ axle { position -49; wheel_diameter 16; powered true; };
};
locomotive 33961
name "BR 86";
function 0 "light";
function 2 "telex";
+
+ length 144;
+ width 33;
+ height 33;
+
+ bogie
+ {
+ position 36;
+ axle { position 23; wheel_diameter 9; };
+ };
+ axle { position 29; wheel_diameter 16; powered true; };
+ axle { position 9.67; wheel_diameter 16; powered true; };
+ axle { position -9.67; wheel_diameter 16; powered true; };
+ axle { position -29; wheel_diameter 16; powered true; };
+ bogie
+ {
+ position -36;
+ axle { position -23; wheel_diameter 9; };
+ };
};
locomotive 36850
{
name "BR 185";
function 0 "light";
+
+ length 205;
+ width 33;
+ height 33;
+
+ bogie
+ {
+ position 60;
+ axle { position 15; wheel_diameter 14; powered true; };
+ axle { position -15; wheel_diameter 14; powered true; };
+ };
+ bogie
+ {
+ position -60;
+ axle { position 15; wheel_diameter 14; powered true; };
+ axle { position -15; wheel_diameter 14; powered true; };
+ };
};
locomotive 37225
{
name "BR 194";
function 0 "light";
+
+ length 200;
+ width 33;
+ height 33;
+
+ bogie
+ {
+ position 45;
+ // Note: front bogie not powered in model
+ axle { position 34; wheel_diameter 14; powered true; };
+ axle { position 6; wheel_diameter 14; powered true; };
+ axle { position -19; wheel_diameter 14; powered true; };
+ };
+ bogie
+ {
+ position -45;
+ axle { position 19; wheel_diameter 14; powered true; };
+ axle { position -6; wheel_diameter 14; powered true; };
+ axle { position -34; wheel_diameter 14; powered true; };
+ };
};
*/
#include <msp/gl/meshbuilder.h>
+#include "libmarklin/locotype.h"
#include "catalogue.h"
#include "tracktype.h"
+#include "vehicletype.h"
using namespace std;
using namespace Msp;
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));
const map<unsigned, TrackType *> &trks = catalogue.get_tracks();
for(map<unsigned, TrackType *>::const_iterator i=trks.begin(); i!=trks.end(); ++i)
return *i->second;
}
+const VehicleType3D &Catalogue3D::get_vehicle(const VehicleType &vt) const
+{
+ map<const VehicleType *, VehicleType3D *>::const_iterator i = vehicles.find(&vt);
+ if(i==vehicles.end())
+ throw KeyError("Unknown vehicle type");
+
+ return *i->second;
+}
+
void Catalogue3D::track_added(const TrackType &track)
{
tracks[&track] = new TrackType3D(*this, track);
}
+void Catalogue3D::loco_added(const LocoType &loco)
+{
+ vehicles[&loco] = new VehicleType3D(*this, loco);
+}
+
void Catalogue3D::build_endpoint_mesh()
{
const Profile &ballast_profile = catalogue.get_ballast_profile();
namespace Marklin {
class TrackType3D;
+class VehicleType3D;
class Catalogue3D
{
private:
Catalogue &catalogue;
std::map<const TrackType *, TrackType3D *> tracks;
+ std::map<const VehicleType *, VehicleType3D *> vehicles;
Msp::GL::Material ballast_material;
Msp::GL::Material rail_material;
Msp::GL::Mesh endpoint_mesh;
const Catalogue &get_catalogue() const { return catalogue; }
const TrackType3D &get_track(const TrackType &) const;
+ const VehicleType3D &get_vehicle(const VehicleType &) const;
const Msp::GL::Material &get_ballast_material() const { return ballast_material; }
const Msp::GL::Material &get_rail_material() const { return rail_material; }
const Msp::GL::Mesh &get_endpoint_mesh() const { return endpoint_mesh; }
private:
void track_added(const TrackType &);
+ void loco_added(const LocoType &);
void build_endpoint_mesh();
};
#include <msp/gl/texture.h>
#include <msp/datafile/parser.h>
#include "layout.h"
+#include "track.h"
+#include "vehicle.h"
using namespace std;
using namespace Msp;
{
layout.signal_track_added.connect(sigc::mem_fun(this, &Layout3D::track_added));
layout.signal_track_removed.connect(sigc::mem_fun(this, &Layout3D::track_removed));
- layout.signal_train_added.connect(sigc::mem_fun(this, &Layout3D::train_added));
+ layout.signal_vehicle_added.connect(sigc::mem_fun(this, &Layout3D::vehicle_added));
const set<Track *> <racks = layout.get_tracks();
for(set<Track *>::iterator i=ltracks.begin(); i!=ltracks.end(); ++i)
{
while(!tracks.empty())
delete tracks.front();
- while(!trains.empty())
- delete trains.front();
+ while(!vehicles.empty())
+ delete vehicles.front();
}
void Layout3D::add_track(Track3D &t)
Track3D *track = 0;
unsigned track_depth = numeric_limits<unsigned>::max();
for(vector<GL::SelectRecord>::iterator i=select_buf.begin(); i!=select_buf.end(); ++i)
- if(i->min_depth<track_depth)
+ if(i->min_depth<track_depth && !i->names.empty())
{
track = reinterpret_cast<Track3D *>(i->names.back());
track_depth = i->min_depth;
return track;
}
-void Layout3D::add_train(Train3D &t)
+void Layout3D::add_vehicle(Vehicle3D &v)
{
- trains.push_back(&t);
+ vehicles.push_back(&v);
}
-void Layout3D::remove_train(Train3D &t)
+void Layout3D::remove_vehicle(Vehicle3D &v)
{
- list<Train3D *>::iterator i = find(trains.begin(), trains.end(), &t);
- if(i!=trains.end())
- trains.erase(i);
+ list<Vehicle3D *>::iterator i = find(vehicles.begin(), vehicles.end(), &v);
+ if(i!=vehicles.end())
+ vehicles.erase(i);
}
-Train3D &Layout3D::get_train(const Train &t) const
+Vehicle3D &Layout3D::get_vehicle(const Vehicle &v) const
{
- for(list<Train3D *>::const_iterator i=trains.begin(); i!=trains.end(); ++i)
- if(&(*i)->get_train()==&t)
+ for(list<Vehicle3D *>::const_iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
+ if(&(*i)->get_vehicle()==&v)
return **i;
- throw KeyError("Unknown train");
+ throw KeyError("Unknown vehicle");
}
void Layout3D::track_added(Track &t)
}
}
-void Layout3D::train_added(Train &t)
+void Layout3D::vehicle_added(Vehicle &v)
{
- new Train3D(*this, t);
+ new Vehicle3D(*this, v);
}
} // namespace Marklin
#include <msp/gl/scene.h>
#include "libmarklin/layout.h"
#include "catalogue.h"
-#include "track.h"
-#include "train.h"
namespace Marklin {
+class Track3D;
+class Vehicle3D;
+
class Layout3D: public sigc::trackable
{
private:
Layout &layout;
Catalogue3D catalogue;
std::list<Track3D *> tracks;
- std::list<Train3D *> trains;
+ std::list<Vehicle3D *> vehicles;
Msp::GL::Scene scene;
Msp::GL::Scene ep_scene;
Msp::GL::Scene path_scene;
Track3D &get_track(const Track &) const;
Track3D *pick_track(float, float, float) const;
- void add_train(Train3D &);
- void remove_train(Train3D &);
- Train3D &get_train(const Train &) const;
+ void add_vehicle(Vehicle3D &);
+ void remove_vehicle(Vehicle3D &);
+ Vehicle3D &get_vehicle(const Vehicle &) const;
Msp::GL::Scene &get_scene() { return scene; }
Msp::GL::Scene &get_endpoint_scene() { return ep_scene; }
private:
void track_added(Track &);
void track_removed(Track &);
- void train_added(Train &);
+ void vehicle_added(Vehicle &);
};
} // namespace Marklin
+++ /dev/null
-/* $Id$
-
-This file is part of the MSP Märklin suite
-Copyright © 2010 Mikkosoft Productions, Mikko Rasa
-Distributed under the GPL
-*/
-
-#include "layout.h"
-#include "train.h"
-
-namespace Marklin {
-
-Train3D::Train3D(Layout3D &l, const Train &t):
- layout(l),
- train(t)
-{
- layout.add_train(*this);
-}
-
-Train3D::~Train3D()
-{
- layout.remove_train(*this);
-}
-
-Point Train3D::get_node() const
-{
- const Point &pos = train.get_position();
- return Point(pos.x, pos.y, pos.z+0.02);
-}
-
-} // namespace Marklin
+++ /dev/null
-/* $Id$
-
-This file is part of the MSP Märklin suite
-Copyright © 2010 Mikkosoft Productions, Mikko Rasa
-Distributed under the GPL
-*/
-
-#ifndef MARKLIN3D_TRAIN_H_
-#define MARKLIN3D_TRAIN_H_
-
-#include "libmarklin/train.h"
-#include "object.h"
-
-namespace Marklin {
-
-class Layout3D;
-
-class Train3D: public Object3D
-{
-private:
- Layout3D &layout;
- const Train &train;
-
-public:
- Train3D(Layout3D &, const Train &);
- ~Train3D();
-
- const Train &get_train() const { return train; }
-
- virtual Point get_node() const;
-};
-
-} // namespace Marklin
-
-#endif
--- /dev/null
+/* $Id$
+
+This file is part of the MSP Märklin suite
+Copyright © 2010 Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#include <cmath>
+#include <msp/gl/matrix.h>
+#include "layout.h"
+#include "vehicle.h"
+#include "vehicletype.h"
+
+using namespace Msp;
+
+namespace Marklin {
+
+Vehicle3D::Vehicle3D(Layout3D &l, Vehicle &v):
+ layout(l),
+ vehicle(v),
+ type(layout.get_catalogue().get_vehicle(vehicle.get_type()))
+{
+ layout.add_vehicle(*this);
+ layout.get_scene().add(*this);
+}
+
+Vehicle3D::~Vehicle3D()
+{
+ layout.remove_vehicle(*this);
+ layout.get_scene().remove(*this);
+}
+
+Point Vehicle3D::get_node() const
+{
+ Point p = vehicle.get_position();
+ return Point(p.x, p.y, p.z+0.01+vehicle.get_type().get_height());
+}
+
+void Vehicle3D::render(const GL::Tag &tag) const
+{
+ if(tag==0)
+ {
+ GL::PushMatrix push_mat;
+
+ const Point &pos = vehicle.get_position();
+ GL::translate(pos.x, pos.y, pos.z+0.01);
+ GL::rotate(vehicle.get_direction()*180/M_PI, 0, 0, 1);
+
+ type.get_body_mesh().draw();
+ }
+}
+
+} // namespace Marklin
--- /dev/null
+/* $Id$
+
+This file is part of the MSP Märklin suite
+Copyright © 2010 Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#ifndef LIBMARKLIN3D_VEHICLE_H_
+#define LIBMARKLIN3D_VEHICLE_H_
+
+#include <msp/gl/renderable.h>
+#include "libmarklin/vehicle.h"
+#include "object.h"
+
+namespace Marklin {
+
+class Layout3D;
+class VehicleType3D;
+
+class Vehicle3D: public Object3D, public Msp::GL::Renderable
+{
+private:
+ Layout3D &layout;
+ Vehicle &vehicle;
+ const VehicleType3D &type;
+
+public:
+ Vehicle3D(Layout3D &, Vehicle &);
+ ~Vehicle3D();
+
+ Vehicle &get_vehicle() const { return vehicle; }
+
+ virtual Point get_node() const;
+
+ virtual void render(const Msp::GL::Tag &) const;
+};
+
+} // namespace Marklin
+
+#endif
--- /dev/null
+/* $Id$
+
+This file is part of the MSP Märklin suite
+Copyright © 2010 Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#include <msp/gl/meshbuilder.h>
+#include <msp/gl/vector.h>
+#include "vehicletype.h"
+
+using namespace Msp;
+
+namespace Marklin {
+
+VehicleType3D::VehicleType3D(Catalogue3D &, const VehicleType &vt):
+ body_mesh((GL::NORMAL3, GL::VERTEX3))
+{
+ GL::Vector3 corner(vt.get_length()/2, vt.get_width()/2, vt.get_height());
+
+ GL::MeshBuilder bld(body_mesh);
+ bld.begin(GL::QUADS);
+ bld.normal(1, 0, 0);
+ bld.vertex(corner.x, -corner.y, 0);
+ bld.vertex(corner.x, corner.y, 0);
+ bld.vertex(corner.x, corner.y, corner.z);
+ bld.vertex(corner.x, -corner.y, corner.z);
+ bld.normal(-1, 0, 0);
+ bld.vertex(-corner.x, corner.y, 0);
+ bld.vertex(-corner.x, -corner.y, 0);
+ bld.vertex(-corner.x, -corner.y, corner.z);
+ bld.vertex(-corner.x, corner.y, corner.z);
+ bld.normal(0, 1, 0);
+ bld.vertex(corner.x, corner.y, 0);
+ bld.vertex(-corner.x, corner.y, 0);
+ bld.vertex(-corner.x, corner.y, corner.z);
+ bld.vertex(corner.x, corner.y, corner.z);
+ bld.normal(0, -1, 0);
+ bld.vertex(-corner.x, -corner.y, 0);
+ bld.vertex(corner.x, -corner.y, 0);
+ bld.vertex(corner.x, -corner.y, corner.z);
+ bld.vertex(-corner.x, -corner.y, corner.z);
+ bld.normal(0, 0, 1);
+ bld.vertex(-corner.x, -corner.y, corner.z);
+ bld.vertex(corner.x, -corner.y, corner.z);
+ bld.vertex(corner.x, corner.y, corner.z);
+ bld.vertex(-corner.x, corner.y, corner.z);
+ bld.end();
+}
+
+} // namespace Marklin
--- /dev/null
+/* $Id$
+
+This file is part of the MSP Märklin suite
+Copyright © 2010 Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#ifndef LIBMARKLIN3D_VEHICLETYPE_H_
+#define LIBMARKLIN3D_VEHICLETYPE_H_
+
+#include <msp/gl/mesh.h>
+#include "libmarklin/vehicletype.h"
+
+namespace Marklin {
+
+class Catalogue3D;
+
+class VehicleType3D
+{
+private:
+ Msp::GL::Mesh body_mesh;
+
+public:
+ VehicleType3D(Catalogue3D &, const VehicleType &);
+
+ const Msp::GL::Mesh &get_body_mesh() const { return body_mesh; }
+};
+
+} // namespace Marklin
+
+#endif
#include "libmarklin/driver.h"
#include "libmarklin/tracktype.h"
#include "3d/path.h"
+#include "3d/track.h"
+#include "3d/vehicle.h"
#include "engineer.h"
#include "mainpanel.h"
#include "trainpanel.h"
train_panels.push_back(tpanel);
tpanel->set_visible(true);
- Train3D &t3d = layout_3d.get_train(train);
- overlay->set_label(t3d, train.get_name());
- train.signal_name_changed.connect(sigc::bind<0>(sigc::mem_fun(overlay, &Overlay3D::set_label), sigc::ref(t3d)));
+ Vehicle3D &loco3d = layout_3d.get_vehicle(train.get_vehicle(0));
+ overlay->set_label(loco3d, train.get_name());
+ train.signal_name_changed.connect(sigc::bind<0>(sigc::mem_fun(overlay, &Overlay3D::set_label), sigc::ref(loco3d)));
GL::Color best_color;
float best_d_sq = 0;
#include "libmarklin/train.h"
#include "3d/layout.h"
#include "3d/overlay.h"
+#include "3d/path.h"
#include "network/server.h"
#include "options.h"
class LocoType;
class TrackType;
+class VehicleType;
class Catalogue
{
signal_train_removed.emit(t);
}
+void Layout::add_vehicle(Vehicle &v)
+{
+ if(vehicles.insert(&v).second)
+ signal_vehicle_added.emit(v);
+}
+
+void Layout::remove_vehicle(Vehicle &v)
+{
+ if(vehicles.erase(&v))
+ signal_vehicle_removed.emit(v);
+}
+
void Layout::tick()
{
if(driver)
class Route;
class Track;
class Train;
+class Vehicle;
class Layout
{
sigc::signal<void, Route &> signal_route_removed;
sigc::signal<void, Train &> signal_train_added;
sigc::signal<void, Train &> signal_train_removed;
+ sigc::signal<void, Vehicle &> signal_vehicle_added;
+ sigc::signal<void, Vehicle &> signal_vehicle_removed;
sigc::signal<void, Block &, Train *> signal_block_reserved;
private:
std::map<std::string, Route *> routes;
std::set<Block *> blocks;
std::map<unsigned, Train *> trains;
+ std::set<Vehicle *> vehicles;
Msp::Time::TimeStamp last_tick;
public:
const std::map<unsigned, Train *> &get_trains() const { return trains; }
void remove_train(Train &);
+ void add_vehicle(Vehicle &);
+ void remove_vehicle(Vehicle &);
+
void tick();
void save(const std::string &);
namespace Marklin {
LocoType::LocoType(unsigned an):
- art_nr(an)
+ VehicleType(an)
{ }
unsigned LocoType::get_max_function() const
LocoType::Loader::Loader(LocoType <):
- Msp::DataFile::BasicLoader<LocoType>(lt)
+ VehicleType::Loader(lt)
{
add("function", &Loader::function);
- add("name", &LocoType::name);
}
void LocoType::Loader::function(unsigned i, const string &f)
{
- obj.funcs[i] = f;
+ static_cast<LocoType &>(obj).funcs[i] = f;
}
} // namespace Marklin
#ifndef LIBMARKLIN_LOCOTYPE_H_
#define LIBMARKLIN_LOCOTYPE_H_
-#include <msp/datafile/loader.h>
+#include "vehicletype.h"
namespace Marklin {
-class LocoType
+class LocoType: public VehicleType
{
public:
- class Loader: public Msp::DataFile::BasicLoader<LocoType>
+ class Loader: public VehicleType::Loader
{
public:
Loader(LocoType &);
public:
LocoType(unsigned);
- unsigned get_article_number() const { return art_nr; }
- const std::string &get_name() const { return name; }
unsigned get_max_function() const;
const std::map<unsigned, std::string> &get_functions() const { return funcs; }
};
float s = sin(rot);
p.pos = Point(pos.x+c*p.pos.x-s*p.pos.y, pos.y+s*p.pos.x+c*p.pos.y, 0);
+ p.dir += rot;
if(type.get_endpoints().size()==2)
{
float len = type.get_path_length(path);
return p;
}
+TrackPoint Track::get_point(unsigned epi, float d) const
+{
+ return get_point(epi, active_path, d);
+}
+
void Track::save(list<DataFile::Statement> &st) const
{
st.push_back((DataFile::Statement("position"), pos.x, pos.y, pos.z));
Track *get_link(unsigned) const;
unsigned traverse(unsigned, unsigned) const;
TrackPoint get_point(unsigned, unsigned, float) const;
+ TrackPoint get_point(unsigned, float) const;
void save(std::list<Msp::DataFile::Statement> &) const;
private:
#include "route.h"
#include "tracktype.h"
#include "train.h"
+#include "vehicle.h"
using namespace std;
using namespace Msp;
travel_dist(0),
travel_speed(0),
pure_speed(false),
- real_speed(15),
- cur_track(0)
+ real_speed(15)
{
+ vehicles.push_back(new Vehicle(layout, loco_type));
+
layout.add_train(*this);
layout.get_driver().add_loco(address);
Train::~Train()
{
+ for(vector<Vehicle *>::iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
+ delete *i;
layout.remove_train(*this);
}
signal_name_changed.emit(name);
}
+Vehicle &Train::get_vehicle(unsigned i)
+{
+ if(i>=vehicles.size())
+ throw InvalidParameterValue("Vehicle index out of range");
+ return *vehicles[i];
+}
+
+const Vehicle &Train::get_vehicle(unsigned i) const
+{
+ if(i>=vehicles.size())
+ throw InvalidParameterValue("Vehicle index out of range");
+ return *vehicles[i];
+}
+
void Train::set_speed(unsigned speed)
{
if(speed==target_speed)
release_blocks(rsv_blocks);
reverse_blocks(cur_blocks);
- if(cur_track)
- {
- unsigned path = cur_track->get_active_path();
- cur_track_ep = cur_track->traverse(cur_track_ep, path);
- offset = cur_track->get_type().get_path_length(path)-offset;
- }
+ // XXX Do something about the vehicles
}
void Train::set_function(unsigned func, bool state)
stop_timeout = Time::TimeStamp();
}
- if(cur_track)
+ if(current_speed)
{
- unsigned path = cur_track->get_active_path();
-
- offset += get_real_speed(current_speed)*(dt/Time::sec);
- float path_len = cur_track->get_type().get_path_length(path);
- if(offset>path_len)
- {
- unsigned out = cur_track->traverse(cur_track_ep, path);
- Track *next = cur_track->get_link(out);
-
- bool ok = false;
- for(list<BlockRef>::const_iterator i=cur_blocks.begin(); (!ok && i!=cur_blocks.end()); ++i)
- ok = i->block->get_tracks().count(next);
+ Track *track = vehicles[0]->get_track();
- if(ok)
- {
- if(next)
- cur_track_ep = next->get_endpoint_by_link(*cur_track);
- cur_track = next;
- offset = 0;
- }
- else
- offset = path_len-0.001;
- }
+ bool ok = false;
+ for(list<BlockRef>::const_iterator i=cur_blocks.begin(); (!ok && i!=cur_blocks.end()); ++i)
+ ok = i->block->get_tracks().count(track);
- if(cur_track)
- pos = cur_track->get_point(cur_track_ep, path, offset).pos;
+ if(ok)
+ vehicles[0]->advance(get_real_speed(current_speed)*(dt/Time::sec));
}
}
void Train::set_position(const Block::Endpoint &bep)
{
- cur_track = bep.track;
- cur_track_ep = bep.track_ep;
- offset = 0;
- pos = cur_track->get_endpoint_position(cur_track_ep);
+ vehicles[0]->place(bep.track, bep.track_ep, 0, Vehicle::FRONT_AXLE);
}
void Train::release_blocks(list<BlockRef> &blocks)
class LocoType;
class Route;
+class Vehicle;
class Train: public sigc::trackable
{
const LocoType &loco_type;
unsigned address;
std::string name;
+ std::vector<Vehicle *> vehicles;
std::list<BlockRef> cur_blocks;
std::list<BlockRef> rsv_blocks;
Block *pending_block;
bool pure_speed;
std::vector<RealSpeed> real_speed;
- Track *cur_track;
- unsigned cur_track_ep;
- float offset;
- Point pos;
-
public:
Train(Layout &, const LocoType &, unsigned);
~Train();
void set_name(const std::string &);
const std::string &get_name() const { return name; }
+ Vehicle &get_vehicle(unsigned);
+ const Vehicle &get_vehicle(unsigned) const;
+
void set_speed(unsigned);
void set_reverse(bool);
void set_function(unsigned, bool);
int get_entry_to_block(Block &) const;
const std::string &get_status() const { return status; }
- const Point &get_position() const { return pos; }
void tick(const Msp::Time::TimeStamp &, const Msp::Time::TimeDelta &);
--- /dev/null
+/* $Id$
+
+This file is part of the MSP Märklin suite
+Copyright © 2010 Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#include <cmath>
+#include "catalogue.h"
+#include "layout.h"
+#include "track.h"
+#include "tracktype.h"
+#include "vehicle.h"
+#include "vehicletype.h"
+
+using namespace std;
+
+namespace Marklin {
+
+Vehicle::Vehicle(Layout &l, const VehicleType &t):
+ layout(l),
+ type(t),
+ next(0),
+ prev(0),
+ direction(0)
+{
+ layout.add_vehicle(*this);
+}
+
+Vehicle::~Vehicle()
+{
+ layout.remove_vehicle(*this);
+}
+
+void Vehicle::place(Track *t, unsigned e, float o, PlaceMode m)
+{
+ track_pos = TrackPosition(t, e, o);
+ if(m==FRONT_AXLE)
+ {
+ float front = type.get_length()/2;
+ if(!type.get_axles().empty())
+ front = type.get_axles().front().position;
+ if(!type.get_bogies().empty())
+ {
+ const VehicleType::Bogie &bogie = type.get_bogies().front();
+ front = max(front, bogie.position+bogie.axles.front().position);
+ }
+ track_pos.advance(-front);
+ }
+ update_position();
+}
+
+void Vehicle::advance(float d)
+{
+ track_pos.advance(d);
+ update_position();
+}
+
+void Vehicle::update_position()
+{
+ TrackPoint tp;
+
+ const vector<VehicleType::Axle> &axles = type.get_axles();
+ if(axles.size()>=2)
+ tp = get_position(axles.front().position, axles.back().position, track_pos);
+ 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);
+ else
+ tp = track_pos.get_point();
+ }
+ position = tp.pos;
+ direction = tp.dir;
+}
+
+TrackPoint Vehicle::get_position(float front, float back, const TrackPosition &tpos)
+{
+ TrackPosition front_pos = tpos;
+ front_pos.advance(front);
+
+ TrackPosition back_pos = tpos;
+ back_pos.advance(back);
+
+ float target_dist = front-back;
+
+ while(1)
+ {
+ Point front_point = front_pos.get_point().pos;
+ Point back_point = back_pos.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 adjust = target_dist-dist+0.01*layout.get_catalogue().get_scale();
+ front_pos.advance(adjust/2);
+ back_pos.advance(-adjust/2);
+ }
+ else
+ {
+ 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;
+ }
+ }
+}
+
+
+Vehicle::TrackPosition::TrackPosition():
+ track(0),
+ ep(0),
+ offs(0)
+{ }
+
+Vehicle::TrackPosition::TrackPosition(Track *t, unsigned e, float o):
+ track(t),
+ ep(e),
+ offs(o)
+{ }
+
+void Vehicle::TrackPosition::advance(float d)
+{
+ if(!track)
+ return;
+
+ unsigned path = track->get_active_path();
+
+ offs += d;
+ float path_len = track->get_type().get_path_length(path);
+ while(track && offs>=path_len)
+ {
+ unsigned out = track->traverse(ep, path);
+ Track *next = track->get_link(out);
+
+ if(next)
+ {
+ ep = next->get_endpoint_by_link(*track);
+ track = next;
+
+ offs -= path_len;
+ path = track->get_active_path();
+ path_len = track->get_type().get_path_length(path);
+ }
+ else
+ track = 0;
+ }
+
+ while(track && offs<0)
+ {
+ Track *prev = track->get_link(ep);
+ if(prev)
+ {
+ unsigned in = prev->get_endpoint_by_link(*track);
+ track = prev;
+
+ path = track->get_active_path();
+ ep = track->traverse(in, path);
+
+ path_len = track->get_type().get_path_length(path);
+ offs += path_len;
+ }
+ else
+ track = 0;
+ }
+
+ if(!track)
+ {
+ ep = 0;
+ offs = 0;
+ }
+}
+
+TrackPoint Vehicle::TrackPosition::get_point() const
+{
+ if(track)
+ return track->get_point(ep, offs);
+ else
+ return TrackPoint();
+}
+
+} // namespace Marklin
--- /dev/null
+/* $Id$
+
+This file is part of the MSP Märklin suite
+Copyright © 2010 Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#ifndef LIBMARKLIN_VEHICLE_H_
+#define LIBMARKLIN_VEHICLE_H_
+
+#include "geometry.h"
+
+namespace Marklin {
+
+class Layout;
+class Track;
+class VehicleType;
+
+class Vehicle
+{
+public:
+ enum PlaceMode
+ {
+ CENTER,
+ FRONT_AXLE
+ };
+
+private:
+ struct TrackPosition
+ {
+ Track *track;
+ unsigned ep;
+ float offs;
+
+ TrackPosition();
+ TrackPosition(Track *, unsigned, float);
+ void advance(float);
+ TrackPoint get_point() const;
+ };
+
+ Layout &layout;
+ const VehicleType &type;
+ Vehicle *next;
+ Vehicle *prev;
+ TrackPosition track_pos;
+ Point position;
+ float direction;
+
+public:
+ Vehicle(Layout &, const VehicleType &);
+ ~Vehicle();
+
+ const VehicleType &get_type() const { return type; }
+
+ void place(Track *, unsigned, float, PlaceMode = CENTER);
+ void advance(float);
+ Track *get_track() const { return track_pos.track; }
+ const Point &get_position() const { return position; }
+ float get_direction() const { return direction; }
+private:
+ void update_position();
+ TrackPoint get_position(float, float, const TrackPosition &);
+};
+
+} // namespace Marklin
+
+#endif
--- /dev/null
+/* $Id$
+
+This file is part of the MSP Märklin suite
+Copyright © 2010 Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#include "vehicletype.h"
+
+using namespace Msp;
+
+namespace Marklin {
+
+VehicleType::VehicleType(unsigned n):
+ art_nr(n),
+ length(0),
+ width(0),
+ height(0)
+{ }
+
+
+VehicleType::Loader::Loader(VehicleType &vt):
+ DataFile::ObjectLoader<VehicleType>(vt)
+{
+ add("axle", &Loader::axle);
+ add("bogie", &Loader::bogie);
+ add("height", &Loader::height);
+ add("length", &Loader::length);
+ add("name", &VehicleType::name);
+ add("width", &Loader::width);
+}
+
+void VehicleType::Loader::axle()
+{
+ Axle axl;
+ load_sub(axl);
+ obj.axles.push_back(axl);
+}
+
+void VehicleType::Loader::bogie()
+{
+ Bogie bog;
+ load_sub(bog);
+ obj.bogies.push_back(bog);
+}
+
+void VehicleType::Loader::height(float h)
+{
+ obj.height = h/1000;
+}
+
+void VehicleType::Loader::length(float l)
+{
+ obj.length = l/1000;
+}
+
+void VehicleType::Loader::width(float w)
+{
+ obj.width = w/1000;
+}
+
+
+VehicleType::Axle::Loader::Loader(Axle &a):
+ DataFile::ObjectLoader<Axle>(a)
+{
+ add("position", &Loader::position);
+ add("wheel_diameter", &Loader::wheel_diameter);
+ add("powered", &Axle::powered);
+}
+
+void VehicleType::Axle::Loader::position(float p)
+{
+ obj.position = p/1000;
+}
+
+void VehicleType::Axle::Loader::wheel_diameter(float d)
+{
+ obj.wheel_dia = d/1000;
+}
+
+
+VehicleType::Bogie::Loader::Loader(Bogie &b):
+ DataFile::ObjectLoader<Bogie>(b)
+{
+ add("position", &Loader::position);
+ add("axle", &Loader::axle);
+}
+
+void VehicleType::Bogie::Loader::axle()
+{
+ Axle axl;
+ load_sub(axl);
+ obj.axles.push_back(axl);
+}
+
+void VehicleType::Bogie::Loader::position(float p)
+{
+ obj.position = p/1000;
+}
+
+} // namespace Marklin
--- /dev/null
+/* $Id$
+
+This file is part of the MSP Märklin suite
+Copyright © 2010 Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#ifndef LIBMARKLIN_VEHICLETYPE_H_
+#define LIBMARKLIN_VEHICLETYPE_H_
+
+#include <msp/datafile/objectloader.h>
+
+namespace Marklin {
+
+class VehicleType
+{
+public:
+ class Loader: public Msp::DataFile::ObjectLoader<VehicleType>
+ {
+ public:
+ Loader(VehicleType &);
+ private:
+ void axle();
+ void bogie();
+ void height(float);
+ void length(float);
+ void width(float);
+ };
+
+ struct Axle
+ {
+ class Loader: public Msp::DataFile::ObjectLoader<Axle>
+ {
+ public:
+ Loader(Axle &);
+ private:
+ void position(float);
+ void wheel_diameter(float);
+ };
+
+ float position;
+ float wheel_dia;
+ bool powered;
+ };
+
+ struct Bogie
+ {
+ class Loader: public Msp::DataFile::ObjectLoader<Bogie>
+ {
+ public:
+ Loader(Bogie &);
+ private:
+ void axle();
+ void position(float);
+ };
+
+ float position;
+ std::vector<Axle> axles;
+ };
+
+private:
+ unsigned art_nr;
+ std::string name;
+ float length;
+ float width;
+ float height;
+ std::vector<Axle> axles;
+ std::vector<Bogie> bogies;
+
+public:
+ VehicleType(unsigned);
+
+ unsigned get_article_number() const { return art_nr; }
+ const std::string &get_name() const { return name; }
+ float get_length() const { return length; }
+ float get_width() const { return width; }
+ float get_height() const { return height; }
+ const std::vector<Axle> &get_axles() const { return axles; }
+ const std::vector<Bogie> &get_bogies() const { return bogies; }
+};
+
+} // namespace Marklin
+
+#endif