]> git.tdb.fi Git - r2c2.git/blobdiff - source/libr2c2/vehicletype.cpp
Also store gauge in VehicleType
[r2c2.git] / source / libr2c2 / vehicletype.cpp
index 3d695f82622ada1cf4e269ef6cb78dbfb10331ef..58ef1d468cb4946294a166f85cf020a862ac8748 100644 (file)
@@ -1,10 +1,8 @@
-/* $Id$
-
-This file is part of R²C²
-Copyright © 2010  Mikkosoft Productions, Mikko Rasa
-Distributed under the GPL
-*/
-
+#include <msp/core/maputils.h>
+#include <msp/geometry/box.h>
+#include <msp/geometry/transformedshape.h>
+#include <msp/strings/regex.h>
+#include <msp/strings/format.h>
 #include "vehicletype.h"
 
 using namespace std;
@@ -13,11 +11,15 @@ using namespace Msp;
 namespace R2C2 {
 
 VehicleType::VehicleType(const ArticleNumber &an):
-       art_nr(an),
+       ObjectType(an),
        locomotive(false),
+       swap_direction(false),
+       gauge(1.524),
        length(0),
        width(0),
-       height(0)
+       height(0),
+       rotate_object(false),
+       max_speed(0)
 { }
 
 unsigned VehicleType::get_max_function() const
@@ -27,34 +29,62 @@ unsigned VehicleType::get_max_function() const
        return (--functions.end())->first;
 }
 
+const VehicleType::Axle &VehicleType::get_axle(unsigned i) const
+{
+       if(i>=axles.size())
+               throw out_of_range("VehicleType::get_axle");
+       return axles[i];
+}
+
+const VehicleType::Axle &VehicleType::get_fixed_axle(unsigned i) const
+{
+       if(i>=fixed_axles.size())
+               throw out_of_range("VehicleType::get_fixed_axle");
+       return *fixed_axles[i];
+}
+
+const VehicleType::Bogie &VehicleType::get_bogie(unsigned i) const
+{
+       if(i>=bogies.size())
+               throw out_of_range("VehicleType::get_bogie");
+       return bogies[i];
+}
+
+const VehicleType::Axle &VehicleType::get_bogie_axle(unsigned i, unsigned j) const
+{
+       if(i>=bogies.size())
+               throw out_of_range("VehicleType::get_bogie_axle");
+       if(j>=bogies[i].axles.size())
+               throw out_of_range("VehicleType::get_bogie_axle");
+       return *bogies[i].axles[j];
+}
+
+const VehicleType::Rod &VehicleType::get_rod(unsigned i) const
+{
+       if(i>=rods.size())
+               throw out_of_range("VehicleType::get_rod");
+       return rods[i];
+}
+
 float VehicleType::get_front_axle_offset() const
 {
-       float front = length/2;
        if(!axles.empty())
-               front = axles.front().position;
-       if(!bogies.empty())
-       {
-               const Bogie &bogie = bogies.front();
-               front = max(front, bogie.position+bogie.axles.front().position);
-       }
-       return front;
+               return axles.front().position;
+       return length/2;
 }
 
 float VehicleType::get_back_axle_offset() const
 {
-       float back = -length/2;
        if(!axles.empty())
-               back = axles.back().position;
-       if(!bogies.empty())
-       {
-               const Bogie &bogie = bogies.back();
-               back = min(back, bogie.position+bogie.axles.back().position);
-       }
-       return back;
+               return axles.back().position;
+       return -length/2;
 }
 
 
 VehicleType::Axle::Axle():
+       index(0),
+       bogie(0),
+       local_position(0),
        position(0),
        wheel_dia(0),
        powered(false)
@@ -67,20 +97,59 @@ VehicleType::Bogie::Bogie():
 { }
 
 
+VehicleType::Rod::Rod():
+       mirror_object(false)
+{ }
+
+
 VehicleType::Loader::Loader(VehicleType &vt):
-       DataFile::ObjectLoader<VehicleType>(vt)
+       DataFile::DerivedObjectLoader<VehicleType, ObjectType::Loader>(vt)
 {
        add("axle",       &Loader::axle);
        add("bogie",      &Loader::bogie);
        add("function",   &Loader::function);
+       add("gauge",      &Loader::gauge);
        add("height",     &Loader::height);
        add("length",     &Loader::length);
        add("locomotive", &VehicleType::locomotive);
+       add("maximum_speed", &VehicleType::max_speed);
+       add("mirror_rods", &Loader::mirror_rods);
        add("object",     &VehicleType::object);
-       add("name",       &VehicleType::name);
+       add("rod",        &Loader::rod);
+       add("rotate_object", &VehicleType::rotate_object);
+       add("swap_direction", &VehicleType::swap_direction);
        add("width",      &Loader::width);
 }
 
+void VehicleType::Loader::finish()
+{
+       for(unsigned i=0; i<obj.bogies.size(); ++i)
+       {
+               obj.bogies[i].index = i;
+               for(unsigned j=0; j<obj.bogies[i].axles.size(); ++j)
+               {
+                       obj.bogies[i].axles[j] = &obj.axles[obj.bogies[i].first_axle+j];
+                       obj.bogies[i].axles[j]->bogie = &obj.bogies[i];
+                       obj.bogies[i].axles[j]->position += obj.bogies[i].position;
+               }
+       }
+
+       for(unsigned i=0; i<obj.axles.size(); ++i)
+       {
+               obj.axles[i].index = i;
+               if(!obj.axles[i].bogie)
+                       obj.fixed_axles.push_back(&obj.axles[i]);
+       }
+
+       for(TagMap::const_iterator i=rod_tags.begin(); i!=rod_tags.end(); ++i)
+               if(i->second>=0x10000)
+                       throw runtime_error(format("unresolved reference to %s\n", i->first));
+
+       obj.shape = new Geometry::TransformedShape<float, 3>(
+               Geometry::Box<float>(obj.length, obj.width, obj.height),
+               Transform::translation(Vector(0, 0, obj.height/2)));
+}
+
 void VehicleType::Loader::axle()
 {
        Axle axl;
@@ -91,7 +160,8 @@ void VehicleType::Loader::axle()
 void VehicleType::Loader::bogie()
 {
        Bogie bog;
-       load_sub(bog);
+       Bogie::Loader ldr(obj, bog);
+       load_sub_with(ldr);
        obj.bogies.push_back(bog);
 }
 
@@ -100,6 +170,11 @@ void VehicleType::Loader::function(unsigned i, const string &f)
        obj.functions[i] = f;
 }
 
+void VehicleType::Loader::gauge(float g)
+{
+       obj.gauge = g/1000;
+}
+
 void VehicleType::Loader::height(float h)
 {
        obj.height = h/1000;
@@ -110,6 +185,65 @@ void VehicleType::Loader::length(float l)
        obj.length = l/1000;
 }
 
+void VehicleType::Loader::mirror_rods()
+{
+       MirrorParametersLoader params;
+       load_sub_with(params);
+       Regex r_filter(params.filter);
+
+       vector<unsigned> mirror_indices(obj.rods.size(), 0);
+       for(TagMap::const_iterator i=rod_tags.begin(); i!=rod_tags.end(); ++i)
+               if(i->second<0x10000 && r_filter.match(i->first))
+                       mirror_indices[i->second] = 1;
+
+       for(unsigned i=0, j=obj.rods.size(); i<mirror_indices.size(); ++i)
+               if(mirror_indices[i])
+                       mirror_indices[i] = j++;
+
+       Transform axle_trans = Transform::rotation(params.phase_offset, Vector(0, 1, 0));
+
+       for(unsigned i=0; i<mirror_indices.size(); ++i)
+       {
+               if(!mirror_indices[i])
+                       continue;
+
+               Rod mr = obj.rods[i];
+               mr.initial_position.y = -mr.initial_position.y;
+               mr.mirror_object = !mr.mirror_object;
+               for(vector<RodConstraint>::iterator j=mr.constraints.begin(); j!=mr.constraints.end(); ++j)
+               {
+                       j->target_position.y = -j->target_position.y;
+                       j->local_position.y = -j->local_position.y;
+                       j->axis.y = -j->axis.y;
+                       if(j->target==RodConstraint::ROD && mirror_indices[j->target_index])
+                               j->target_index = mirror_indices[j->target_index];
+                       else if(j->target==RodConstraint::AXLE)
+                               j->target_position = axle_trans.transform(j->target_position);
+               }
+
+               obj.rods.push_back(mr);
+       }
+}
+
+void VehicleType::Loader::rod(const string &t)
+{
+       Rod rd;
+       Rod::Loader ldr(rd, rod_tags);
+       load_sub_with(ldr);
+
+       unsigned n = obj.rods.size();
+       if(rod_tags.count(t))
+       {
+               unsigned p = rod_tags[t];
+               for(vector<Rod>::iterator i=obj.rods.begin(); i!=obj.rods.end(); ++i)   
+                       for(vector<RodConstraint>::iterator j=i->constraints.begin(); j!=i->constraints.end(); ++j)
+                               if(j->target_index==p)
+                                       j->target_index = n;
+       }
+       rod_tags[t] = n;
+       obj.rods.push_back(rd);
+}
+
 void VehicleType::Loader::width(float w)
 {
        obj.width = w/1000;
@@ -127,7 +261,8 @@ VehicleType::Axle::Loader::Loader(Axle &a):
 
 void VehicleType::Axle::Loader::position(float p)
 {
-       obj.position = p/1000;
+       obj.local_position = p/1000;
+       obj.position = obj.local_position;
 }
 
 void VehicleType::Axle::Loader::wheel_diameter(float d)
@@ -136,8 +271,9 @@ void VehicleType::Axle::Loader::wheel_diameter(float d)
 }
 
 
-VehicleType::Bogie::Loader::Loader(Bogie &b):
-       DataFile::ObjectLoader<Bogie>(b)
+VehicleType::Bogie::Loader::Loader(VehicleType &t, Bogie &b):
+       DataFile::ObjectLoader<Bogie>(b),
+       parent(t)
 {
        add("axle",          &Loader::axle);
        add("object",        &Bogie::object);
@@ -149,7 +285,11 @@ void VehicleType::Bogie::Loader::axle()
 {
        Axle axl;
        load_sub(axl);
-       obj.axles.push_back(axl);
+       if(obj.axles.empty())
+               obj.first_axle = parent.axles.size();
+       parent.axles.push_back(axl);
+       // Actual pointers will be filled after everything is loaded
+       obj.axles.push_back(0);
 }
 
 void VehicleType::Bogie::Loader::position(float p)
@@ -157,4 +297,103 @@ void VehicleType::Bogie::Loader::position(float p)
        obj.position = p/1000;
 }
 
+
+VehicleType::RodConstraint::RodConstraint():
+       type(MOVE),
+       target(BODY),
+       target_index(0)
+{ }
+
+
+VehicleType::RodConstraint::Loader::Loader(RodConstraint &c, TagMap &t):
+       DataFile::ObjectLoader<RodConstraint>(c),
+       tags(t)
+{
+       add("axis",            &Loader::axis);
+       add("local_position",  &Loader::local_position);
+       add("target_axle",     &Loader::target_axle);
+       add("target_position", &Loader::target_position);
+       add("target_rod",      &Loader::target_rod);
+}
+
+void VehicleType::RodConstraint::Loader::axis(float x, float y, float z)
+{
+       obj.axis = Vector(x, y, z);
+       obj.axis.normalize();
+}
+
+void VehicleType::RodConstraint::Loader::local_position(float x, float y, float z)
+{
+       obj.local_position = Vector(x/1000, y/1000, z/1000);
+}
+
+void VehicleType::RodConstraint::Loader::target_axle(unsigned i)
+{
+       obj.target = AXLE;
+       obj.target_index = i;
+       // TODO check range
+}
+
+void VehicleType::RodConstraint::Loader::target_position(float x, float y, float z)
+{
+       obj.target_position = Vector(x/1000, y/1000, z/1000);
+}
+
+void VehicleType::RodConstraint::Loader::target_rod(const string &n)
+{
+       obj.target = ROD;
+       TagMap::iterator i = tags.find(n);
+       if(i!=tags.end())
+               obj.target_index = i->second;
+       else
+       {
+               obj.target_index = 0x10000+tags.size();
+               tags[n] = obj.target_index;
+       }
+}
+
+
+VehicleType::Rod::Loader::Loader(Rod &r, TagMap &t):
+       DataFile::ObjectLoader<Rod>(r),
+       tags(t)
+{
+       add("initial_position", &Loader::initial_position);
+       add("mirror_object", &Rod::mirror_object);
+       add("move", &Loader::constraint<RodConstraint::MOVE>);
+       add("object", &Rod::object);
+       add("rotate", &Loader::constraint<RodConstraint::ROTATE>);
+       add("slide", &Loader::constraint<RodConstraint::SLIDE>);
+}
+
+template<VehicleType::RodConstraint::Type t>
+void VehicleType::Rod::Loader::constraint()
+{
+       RodConstraint cns;
+       cns.type = t;
+       load_sub(cns, tags);
+       obj.constraints.push_back(cns);
+}
+
+void VehicleType::Rod::Loader::initial_position(float x, float y, float z)
+{
+       obj.initial_position = Vector(x/1000, y/1000, z/1000);
+}
+
+
+VehicleType::MirrorParametersLoader::MirrorParametersLoader()
+{
+       add("filter", &MirrorParametersLoader::filt);
+       add("phase_offset", &MirrorParametersLoader::phase_offs);
+}
+
+void VehicleType::MirrorParametersLoader::filt(const string &f)
+{
+       filter = f;
+}
+
+void VehicleType::MirrorParametersLoader::phase_offs(float o)
+{
+       phase_offset = Angle::from_degrees(o);
+}
+
 } // namespace R2C2