]> git.tdb.fi Git - r2c2.git/blobdiff - source/libr2c2/vehicle.cpp
Make the axles of vehicles rotate when moving
[r2c2.git] / source / libr2c2 / vehicle.cpp
index e0a5c9695f210e11938ab2d4c22b4d69d1d26d10..578707a63ef5c47eab1bef45104a0c269fe60a6c 100644 (file)
@@ -27,10 +27,17 @@ Vehicle::Vehicle(Layout &l, const VehicleType &t):
        prev(0),
        direction(0),
        bogie_dirs(type.get_bogies().size()),
+       axle_angles(1),
+       rods(type.get_rods().size()),
        front_sensor(0),
        back_sensor(0)
 {
        layout.add_vehicle(*this);
+
+       axle_angles.front().resize(type.get_axles().size(), 0.0f);
+       const vector<VehicleType::Bogie> &bogies = type.get_bogies();
+       for(vector<VehicleType::Bogie>::const_iterator i=bogies.begin(); i!=bogies.end(); ++i)
+               axle_angles.push_back(vector<float>(i->axles.size(), 0.0f));
 }
 
 Vehicle::~Vehicle()
@@ -118,6 +125,7 @@ void Vehicle::advance(float d)
 {
        track_pos.advance(d);
        update_position();
+       turn_axles(d);
        propagate_position();
 }
 
@@ -128,6 +136,36 @@ float Vehicle::get_bogie_direction(unsigned i) const
        return bogie_dirs[i];
 }
 
+float Vehicle::get_axle_angle(unsigned i) const
+{
+       if(i>=axle_angles[0].size())
+               throw InvalidParameterValue("Axle index out of range");
+       return axle_angles[0][i];
+}
+
+float Vehicle::get_bogie_axle_angle(unsigned i, unsigned j) const
+{
+       if(i+1>=axle_angles.size())
+               throw InvalidParameterValue("Bogie index out of range");
+       if(j>=axle_angles[i+1].size())
+               throw InvalidParameterValue("Axle index out of range");
+       return axle_angles[i+1][j];
+}
+
+const Point &Vehicle::get_rod_position(unsigned i) const
+{
+       if(i>=rods.size())
+               throw InvalidParameterValue("Rod index out of range");
+       return rods[i].position;
+}
+
+float Vehicle::get_rod_angle(unsigned i) const
+{
+       if(i>=rods.size())
+               throw InvalidParameterValue("Rod index out of range");
+       return rods[i].angle;
+}
+
 void Vehicle::update_position()
 {
        TrackPoint tp;
@@ -193,6 +231,7 @@ void Vehicle::update_position_from(const Vehicle &veh)
 
        track_pos.advance(sign*(tdist-dist));
        update_position();
+       turn_axles(sign*(tdist-dist));
 }
 
 void Vehicle::propagate_position()
@@ -245,6 +284,81 @@ void Vehicle::check_sensor(float offset, unsigned &sensor)
        }
 }
 
+void Vehicle::turn_axles(float d)
+{
+       const vector<VehicleType::Axle> &axles = type.get_axles();
+       const vector<VehicleType::Bogie> &bogies = type.get_bogies();
+       for(unsigned i=0; i<axle_angles.size(); ++i)
+               for(unsigned j=0; j<axle_angles[i].size(); ++j)
+               {
+                       const VehicleType::Axle &axle = (i==0 ? axles[j] : bogies[i-1].axles[j]);
+                       axle_angles[i][j] += d*2/axle.wheel_dia;
+               }
+
+       update_rods();
+}
+
+void Vehicle::update_rods()
+{
+       const vector<VehicleType::Rod> &trods = type.get_rods();
+       for(unsigned i=0; i<trods.size(); ++i)
+       {
+               const VehicleType::Rod &rod = trods[i];
+               if(rod.pivot==VehicleType::Rod::BODY)
+                       rods[i].position = rod.pivot_point;
+               else if(rod.pivot==VehicleType::Rod::AXLE)
+               {
+                       const VehicleType::Axle &axle = type.get_axles()[rod.pivot_index];
+                       float angle = axle_angles[0][rod.pivot_index];
+                       float c = cos(angle);
+                       float s = sin(angle);
+                       const Point &pp = rod.pivot_point;
+                       rods[i].position = Point(axle.position+pp.x*c+pp.z*s, pp.y, axle.wheel_dia/2+pp.z*c-pp.x*s);
+               }
+               else if(rod.pivot==VehicleType::Rod::ROD)
+               {
+                       float angle = rods[rod.pivot_index].angle;
+                       float c = cos(angle);
+                       float s = sin(angle);
+                       const Point &pos = rods[rod.pivot_index].position;
+                       const Point &off = rod.pivot_point;
+                       rods[i].position = Point(pos.x+off.x*c-off.z*s, pos.y+off.y, pos.z+off.z*c+off.x*s);
+               }
+
+               if(rod.connect_index>=0)
+               {
+                       const VehicleType::Rod &crod = trods[rod.connect_index];
+                       if(rod.limit==VehicleType::Rod::ROTATE && crod.limit==VehicleType::Rod::SLIDE_X)
+                       {
+                               float dx = (rods[rod.connect_index].position.x+rod.connect_offset.x)-rods[i].position.x;
+                               float dz = (rods[rod.connect_index].position.z+rod.connect_offset.z)-rods[i].position.z;
+                               float cd = sqrt(rod.connect_point.x*rod.connect_point.x+rod.connect_point.z*rod.connect_point.z);
+                               float ca = atan2(rod.connect_point.z, rod.connect_point.x);
+                               dx = sqrt(cd*cd-dz*dz)*(dx>0 ? 1 : -1);
+                               rods[i].angle = atan2(dz, dx)-ca;
+                               rods[rod.connect_index].position.x = rods[i].position.x+dx-rod.connect_offset.x;
+                       }
+                       else if(rod.limit==VehicleType::Rod::ROTATE && crod.limit==VehicleType::Rod::ROTATE)
+                       {
+                               float dx = rods[rod.connect_index].position.x-rods[i].position.x;
+                               float dz = rods[rod.connect_index].position.z-rods[i].position.z;
+                               float d = sqrt(dx*dx+dz*dz);
+                               float cd1 = sqrt(rod.connect_point.x*rod.connect_point.x+rod.connect_point.z*rod.connect_point.z);
+                               float cd2 = sqrt(rod.connect_offset.x*rod.connect_offset.x+rod.connect_offset.z*rod.connect_offset.z);
+                               float a = (d*d+cd1*cd1-cd2*cd2)/(2*d);
+                               float b = sqrt(cd1*cd1-a*a);
+                               float sign = (dx*rod.connect_point.z-dz*rod.connect_point.x>0 ? 1 : -1);
+                               float cx = (dx*a-dz*b*sign)/d;
+                               float cz = (dz*a+dx*b*sign)/d;
+                               float ca1 = atan2(rod.connect_point.z, rod.connect_point.x);
+                               float ca2 = atan2(rod.connect_offset.z, rod.connect_offset.x);
+                               rods[i].angle = atan2(cz, cx)-ca1;
+                               rods[rod.connect_index].angle = atan2(cz-dz, cx-dx)-ca2;
+                       }
+               }
+       }
+}
+
 void Vehicle::adjust_for_distance(TrackPosition &front, TrackPosition &back, float tdist, float ratio) const
 {
        float margin = 0.01*layout.get_catalogue().get_scale();
@@ -361,4 +475,9 @@ TrackPoint Vehicle::TrackPosition::get_point() const
                return TrackPoint();
 }
 
+
+Vehicle::Rod::Rod():
+       angle(0)
+{ }
+
 } // namespace R2C2