// Copyright (C) 2001-2019 Sam Varner
//
// This file is part of Vamos Automotive Simulator.
//
// Vamos is free software: you can redistribute it and/or modify it under the terms of
// the GNU General Public License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// Vamos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with Vamos.
// If not, see <http://www.gnu.org/licenses/>.
#include "Wheel.hpp"
#include "../geometry/Constants.hpp"
#include "../media/Ac3d.hpp"
using namespace Vamos_Body;
using namespace Vamos_Geometry;
Wheel::Wheel(double mass, Three_Vector position, double tire_offset, double restitution,
bool driven, Direction side, Tire* tire, Brake* brake)
: Particle(mass, position, Material(Material::RUBBER, 0.0, restitution)),
mp_tire(tire),
mp_brake(brake),
m_driven(driven),
m_side(side)
{}
void Wheel::contact(const Three_Vector& impulse, const Three_Vector& velocity, double distance,
const Three_Vector& normal, const Three_Vector& angular_velocity,
const Material& surface_material)
{
Particle::contact(impulse, rotate_in(velocity), distance, rotate_in(normal),
rotate_in(angular_velocity), surface_material);
m_normal = rotate_in(normal);
m_velocity = -rotate_in(velocity);
// Move the wheel in the suspension z-direction so the contact position is at the
// surface.
//!! For now assume distance was measured in the suspension z-direction.
m_displacement = distance;
translate(rotate_in(Three_Vector::Z * m_displacement));
//!! auto ground_velocity = m_velocity.project(m_normal) - m_velocity;
//!! mp_tire->input(ground_velocity, speed(),
//!! mp_suspension->force().project(m_normal),
//!! mp_suspension->current_camber(m_normal.unit().y),
//!! m_drive_torque + m_braking_torque, mp_brake->is_locked(),
//!! surface_material);
}
void Wheel::propagate(double time)
{
//!! m_rotational_speed
//!! = mp_brake->is_locked()
//!! ? 0.0
//!! : m_rotational_speed + (m_drive_torque - m_braking_torque) * time / m_inertia;
mp_tire->propagate(time);
m_force = mp_tire->force();
m_torque = mp_tire->torque();
m_rotation += m_rotational_speed * time;
}
void Wheel::drive_torque(double torque_in)
{
m_drive_torque = m_driven ? torque_in : 0.0;
}
void Wheel::brake(double factor)
{
//!! m_braking_torque = -mp_brake->torque(factor, mp_tire->rotational_speed());
}
Three_Vector Wheel::contact_position() const
{
return position() + mp_tire->contact_position();
}
void Wheel::reset()
{
Particle::reset();
mp_tire->reset();
}
GLuint Wheel::make_model(std::string file, double scale, const Three_Vector& translation,
const Three_Vector& rotation)
{
return Vamos_Media::Ac3d(file, scale, translation, rotation).build();
}
void Wheel::set_models(std::string slow_file, std::string fast_file, double transition_speed,
std::string stator_file, double stator_offset, double scale,
const Three_Vector& translation, const Three_Vector& rotation)
{
Three_Vector offset;
if (!stator_file.empty())
offset.y += m_side == RIGHT ? stator_offset : -stator_offset;
if (m_slow_wheel_list)
glDeleteLists(m_slow_wheel_list, 1);
m_slow_wheel_list = make_model(slow_file, scale, translation + offset, rotation);
if (m_fast_wheel_list)
glDeleteLists(m_fast_wheel_list, 1);
m_fast_wheel_list = make_model(fast_file, scale, translation + offset, rotation);
m_transition_speed = transition_speed;
if (stator_file.empty())
return;
if (m_stator_list)
glDeleteLists(m_stator_list, 1);
m_stator_list = make_model(stator_file, scale, translation, rotation);
}
void Wheel::transform()
{
glTranslatef(position().x, position().y, position().z);
auto [axis, angle] = axis_angle();
glRotatef(angle, axis.x, axis.y, axis.z);
}
void Wheel::draw()
{
glPushMatrix();
transform();
glCallList(m_stator_list);
if (speed() < m_transition_speed)
{
glRotatef(rad_to_deg(m_rotation), 0.0, 1.0, 0.0);
glCallList(m_slow_wheel_list);
}
else
glCallList(m_fast_wheel_list);
glPopMatrix();
//!! mp_suspension->draw();
}