src/vamos/body/Car.cc

Go to the documentation of this file.
00001 //  Car.cc - a body with wheels.
00002 //
00003 //  Copyright (C) 2001--2004 Sam Varner
00004 //
00005 //  This file is part of Vamos Automotive Simulator.
00006 //
00007 //  This program is free software; you can redistribute it and/or modify
00008 //  it under the terms of the GNU General Public License as published by
00009 //  the Free Software Foundation; either version 2 of the License, or
00010 //  (at your option) any later version.
00011 //
00012 //  This program is distributed in the hope that it will be useful,
00013 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 //  GNU General Public License for more details.
00016 //
00017 //  You should have received a copy of the GNU General Public License
00018 //  along with this program; if not, write to the Free Software
00019 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020 
00021 #include <vamos/body/Aerodynamic_Device.h>
00022 #include <vamos/body/Brake.h>
00023 #include <vamos/body/Car.h>
00024 #include <vamos/body/Clutch.h>
00025 #include <vamos/body/Differential.h>
00026 #include <vamos/body/Engine.h>
00027 #include <vamos/body/Fuel_Tank.h>
00028 #include <vamos/body/Gauge.h>
00029 #include <vamos/body/Particle.h>
00030 #include <vamos/body/Suspension.h>
00031 #include <vamos/body/Tire.h>
00032 #include <vamos/body/Transmission.h>
00033 #include <vamos/body/Wheel.h>
00034 
00035 #include <cassert>
00036 #include <sstream>
00037 #include <iostream>
00038 
00039 using namespace Vamos_Geometry;
00040 
00041 //* Class Key_Control
00042 // The Key_Control class handles gradual application of a control
00043 // that's operated by a button, such as the clutch.  If you're using a
00044 // keyboard instead of a joystick, it also handles steering, gas and
00045 // brake.
00046 
00047 //** Constructor
00048 Vamos_Body::Key_Control::
00049 Key_Control (bool block) :
00050   m_block (block),
00051   m_target_pending (false),
00052   m_value (0.0),
00053   m_target (0.0),
00054   m_next_target (0.0),
00055   m_rate (0.0),
00056   m_next_rate (0.0),
00057   m_delay (0.0),
00058   m_next_delay (0.0),
00059   m_time (0.0),
00060   m_next_time (0.0)
00061 {
00062 }
00063 
00064 // Set the target setting of this control.  NEW_TARGET is the desired
00065 // setting.  TIME is how long it should take for the setting to go
00066 // from 0.0 to 1.0 after waiting for DELAY.  `m_rate' is calculated in
00067 // this function.
00068 void Vamos_Body::
00069 Key_Control::target (double new_target, double time, double delay)
00070 {
00071   if (m_block)
00072     {
00073       if (m_value == m_target)
00074         {
00075           m_target_pending = false;
00076         }
00077       else
00078         {
00079           m_target_pending = true;
00080           m_next_target = new_target;
00081           m_next_time = time;
00082           m_next_delay = delay;
00083           return;
00084         }
00085     }
00086 
00087   m_target = new_target;
00088   m_delay = delay;
00089   m_time = 0.0;
00090 
00091   if (time != 0.0)
00092     {
00093       m_rate = 1.0 / time;
00094       if (m_target < m_value)
00095         {
00096           m_rate = -m_rate;
00097         }
00098     }
00099   else
00100     {
00101       // m_rate == 0.0 means that the value will be immediately set to the
00102       // target.
00103       m_rate = 0.0;
00104     }
00105 }
00106 
00107 // Update the setting of this control.  The setting move toward
00108 // `m_target' by the ammount `m_rate' * TIME.
00109 double Vamos_Body::
00110 Key_Control::update (double time)
00111 {
00112   m_time += time;
00113   if (m_time < m_delay)
00114     {
00115       return m_value;
00116     }
00117 
00118   if (m_rate == 0.0)
00119     {
00120       m_value = m_target;
00121     }
00122   else
00123     {
00124       m_value += m_rate * time;
00125       if (((m_rate > 0.0) && (m_value > m_target))
00126           || ((m_rate < 0.0) && (m_value < m_target)))
00127         {
00128           m_value = m_target;
00129           m_rate = 0.0;
00130         }
00131     }
00132 
00133   if (m_target_pending && (m_value == m_target))
00134     {
00135       target (m_next_target, m_next_time, m_next_delay);
00136     }
00137 
00138   return m_value;
00139 }
00140 
00141 // Go immediately to the target.
00142 void Vamos_Body::
00143 Key_Control::end ()
00144 {
00145   m_value = m_target;
00146   m_time = m_delay;
00147   m_rate = 0.0;
00148 }
00149 
00150 
00151 
00152 //* Class Car
00153 
00154 //** Constructor
00155 Vamos_Body::
00156 Car::Car (const Three_Vector& pos) :
00157   m_chassis (pos),
00158   mp_drivetrain (0),
00159   mp_fuel_tank (0),
00160   m_max_steer_angle (15.0),
00161   m_steer_exponent (1.0),
00162   m_slide (0.0),
00163   m_shift_pending (false),
00164   m_shift_timer (0.0),
00165   m_shift_delay (0.2),
00166   m_new_gear (0),
00167   m_last_gear (0),
00168   m_clutch_key_control (true),
00169   mp_front_particle (0),
00170   m_distance_traveled (0.0),
00171   m_field_of_view (60.0),
00172   m_pan_angle (90.0),
00173   m_show_dashboard_extras (false),
00174   m_sector(-1)
00175 {
00176         controller = 0;
00177         brakesetting = 0;
00178 }
00179 
00180 extern bool verbose_output;
00181 
00182 //** Destructor
00183 // Only the drivetrain member is deleted here.  The rest are deleted
00184 // when the body deletes the particles. 
00185 Vamos_Body::
00186 Car::~Car ()
00187 {
00188         if (verbose_output)
00189                 std::cout << "Car deinit" << std::endl;
00190         
00191         delete mp_drivetrain;
00192         delete mp_fuel_tank;
00193         unsigned int i;
00194         for( i = 0; i < m_wheels.size(); i++ )
00195         {
00196                 delete m_wheels[i];
00197         }
00198         m_wheels.clear ();
00199         
00200         if (verbose_output)
00201                 std::cout << "Car deinit done" << std::endl;
00202 }
00203 
00204 void Vamos_Body::
00205 Car::read (std::string data_dir, std::string car_file)
00206 {
00207         unsigned int i;
00208         
00209   // Remember the file name for re-reading.
00210   if ((data_dir != "") && (car_file != ""))
00211     {
00212       m_data_dir = data_dir;
00213       m_car_file = car_file;
00214     }
00215 
00216         for( i = 0; i < m_wheels.size(); i++ )
00217         {
00218                 delete m_wheels[i];
00219         }
00220         m_wheels.clear ();
00221         
00222         for (std::vector <Particle*>::iterator it = m_chassis.particles ().begin ();
00223         it != m_chassis.particles ().end (); it++)
00224         delete *it;
00225         
00226         m_chassis.particles ().clear ();
00227 
00228 /*      if (USE_XML)
00229                 Car_Reader reader (m_data_dir, "cars/" + m_car_file + "/" + m_car_file + ".xml", this);
00230 */      if (USE_CAR)
00231         {
00232                 bool success = LoadCarDefinition (m_data_dir + "cars/" + m_car_file + "/" + m_car_file + ".car");
00233                 if (!success)
00234                 {
00235                         cout << "Error when loading car definition file:  " << m_data_dir + "cars/" + m_car_file + "/" + m_car_file + ".car" << endl;
00236                 }
00237         }
00238 
00239   // Find the bounding box for the particles.
00240   std::vector <Particle*>::const_iterator it = m_chassis.particles ().begin ();
00241   m_crash_box.front = (*it)->position ()[0];
00242   m_crash_box.back = m_crash_box.front;
00243   m_crash_box.left = (*it)->position ()[1];
00244   m_crash_box.right = m_crash_box.left;
00245   m_crash_box.top = (*it)->position ()[2];
00246   m_crash_box.bottom = m_crash_box.top;
00247 
00248   mp_front_particle = *it;
00249   for (; it != m_chassis.particles ().end (); it++)
00250     {
00251       const Three_Vector& position = (*it)->position ();
00252       if (position [0] > m_crash_box.front)
00253         {
00254           m_crash_box.front = position [0];
00255           mp_front_particle = *it;
00256         }
00257       else if (position [0] < m_crash_box.back)
00258         {
00259           m_crash_box.back = position [0];
00260         }
00261       if (position [1] > m_crash_box.left)
00262         {
00263           m_crash_box.left = position [1];
00264         }
00265       else if (position [1] < m_crash_box.right)
00266         {
00267           m_crash_box.right = position [1];
00268         }
00269       if (position [2] > m_crash_box.top)
00270         {
00271           m_crash_box.top = position [2];
00272         }
00273       else if (position [2] < m_crash_box.bottom)
00274         {
00275           m_crash_box.bottom = position [2];
00276         }
00277     }
00278 }
00279 
00280 // Advance the car in time by TIME.  This method assumes that the
00281 // first four members of m_particles are the left-front, right-front,
00282 // left-rear, and right-rear wheels, and that the front wheels are
00283 // steered and the rear wheels are driven.  Re-define this virtual
00284 // function if you want to change these conditions.
00285 void Vamos_Body::
00286 Car::propagate (double time)
00287 {
00288   // Propagate the key controls.
00289   m_steer_key_control.update (time);
00290   m_gas_key_control.update (time);
00291   m_brake_key_control.update (time);
00292   m_handbrake_key_control.update (time);
00293   m_clutch_key_control.update (time);
00294   m_pan_key_control.update (time);
00295 
00296   // Update the transmission.
00297   assert (mp_drivetrain);
00298   if (m_shift_pending)
00299     {
00300       m_shift_timer += time;
00301       if (m_shift_timer > m_shift_delay)
00302         {
00303           mp_drivetrain->transmission ()->shift (m_new_gear);
00304           m_shift_pending = false;
00305         }
00306     }
00307 
00308   // Update the throttle.
00309   assert (mp_fuel_tank);
00310   double gas = m_gas_key_control.value ();
00311 
00312   // Let the engine know if the fuel tank is empty.
00313   if (mp_fuel_tank->empty ())
00314     {
00315       gas = 0.0;
00316     }
00317   mp_drivetrain->engine ()->out_of_gas (mp_fuel_tank->empty ());
00318 
00319   // Update the fuel tank.
00320   mp_fuel_tank->consume (mp_drivetrain->engine ()->fuel_rate () * time);
00321 
00322   m_slide = 0.0;
00323   double right_wheel_speed = 0.0;
00324   double left_wheel_speed = 0.0;
00325         int count = 0;
00326   for (std::vector <Wheel*>::iterator it = m_wheels.begin ();
00327        it != m_wheels.end ();
00328        it++,count++)
00329     {
00330       // Steer.
00331       if ((*it)->steered ())
00332         {
00333           (*it)->steer (m_steer_key_control.value ());
00334         }
00335 
00336       // Apply the brakes.
00337                 brakesetting = m_brake_key_control.value();
00338                 //if (!(*it)->steered())
00339                 {
00340                         double handbrakesetting = m_handbrake_key_control.value()*(*it)->get_handbrake_multiplier();
00341                         if (handbrakesetting > brakesetting)
00342                                 brakesetting = handbrakesetting;
00343                 }
00344         (*it)->brake (brakesetting);
00345                 //cout << count << ": " << brakesetting << endl;
00346                 
00347       if ((*it)->driven ())
00348         {
00349           // Apply the driving torque.
00350           (*it)->drive_torque (mp_drivetrain->torque ((*it)->side ()));
00351                         
00352                         //cout << mp_drivetrain->torque ((*it)->side ()) << endl;
00353 
00354           if ((*it)->side () == RIGHT)
00355             right_wheel_speed = (*it)->rotational_speed ();
00356           else if ((*it)->side () == LEFT)
00357             left_wheel_speed = (*it)->rotational_speed ();
00358         }
00359 
00360       // Sum the sliding speeds of the tires.
00361       m_slide += (*it)->slide ();
00362     }
00363         
00364   // Update the drivetrain.
00365   mp_drivetrain->input (gas,
00366                         m_clutch_key_control.value (),
00367                         left_wheel_speed, right_wheel_speed);
00368 
00369   // Propagate the base class.
00370   /*mp_drivetrain->find_forces ();
00371   m_chassis.find_forces ();
00372 
00373   mp_drivetrain->propagate (time / 2.0);
00374   m_chassis.propagate (time / 2.0);
00375 
00376   mp_drivetrain->find_forces ();
00377   m_chassis.find_forces ();
00378 
00379   mp_drivetrain->rewind ();
00380   m_chassis.rewind ();
00381 
00382   mp_drivetrain->propagate (time);
00383   m_chassis.propagate (time);
00384   
00385   m_chassis.end_timestep ();
00386   
00387   m_distance_traveled += 
00388     m_chassis.rotate_in (m_chassis.cm_velocity ()) [0] * time;*/
00389   
00390   int iterations = 1;
00391   
00392   int i;
00393   for (i = 0; i < iterations; i++)
00394   {
00395           m_chassis.find_forces ();
00396           m_chassis.propagate (time);
00397           mp_drivetrain->find_forces ();
00398           mp_drivetrain->propagate (time/(float) iterations);
00399           m_chassis.end_timestep();
00400           m_distance_traveled += 
00401         m_chassis.rotate_in (m_chassis.cm_velocity ()) [0] * (time/(float)iterations);
00402   }
00403 }
00404 
00405 // Change the steering angle to ANGLE with a time constant of TIME.
00406 void Vamos_Body::
00407 Car::steer (double angle, double time)
00408 {
00409   double steer_sign = (angle < 0.0) ? -1.0 : 1.0;
00410 
00411   // Apply the non-linearity.
00412   angle = steer_sign * std::pow (std::abs (angle), m_steer_exponent);
00413 
00414   // Set the maximum angle and speed sensitivity.
00415   double sens = 1.0 
00416     / (1.0 + 1.0e-4 * m_steer_speed_sensitivity 
00417        * m_chassis.cm_velocity ().dot (m_chassis.cm_velocity ()));
00418   angle *= m_max_steer_angle * sens;
00419   //printf("%f\n", m_max_steer_angle);
00420   m_steer_key_control.target (angle, time);
00421 }
00422 
00423 // Change the throttle to FACTOR with a time constant of TIME.
00424 void Vamos_Body::
00425 Car::gas (double factor, double time)
00426 {
00427   m_gas_key_control.target (factor, time);
00428 }
00429 
00430 // Change the brakes to FACTOR with a time constant of TIME.
00431 void Vamos_Body::
00432 Car::brake (double factor, double time)
00433 {
00434   m_brake_key_control.target (factor, time);
00435 }
00436 
00437 // Change the handbrakes to FACTOR with a time constant of TIME.
00438 void Vamos_Body::
00439 Car::handbrake (double factor, double time)
00440 {
00441   m_handbrake_key_control.target (factor, time);
00442 }
00443 
00444 // Pan the view.
00445 void Vamos_Body::
00446 Car::pan (double factor, double time)
00447 {
00448   m_pan_key_control.target (factor * m_pan_angle, time / m_pan_angle);
00449 }
00450 
00451 // Shift to the next lower gear.  The chosen gear is returned.
00452 int Vamos_Body::
00453 Car::shift_down ()
00454 {
00455   return shift (mp_drivetrain->transmission ()->gear () - 1);
00456 }
00457 
00458 // Shift to the next higher gear.  The chosen gear is returned.
00459 int Vamos_Body::
00460 Car::shift_up ()
00461 {
00462   return shift (mp_drivetrain->transmission ()->gear () + 1);
00463 }
00464 
00465 // Shift to GEAR.  The chosen gear is returned.
00466 int Vamos_Body::
00467 Car::shift (int gear)
00468 {
00469   // Do the shift if GEAR is accessible.
00470   if ((gear <= mp_drivetrain->transmission ()->forward_gears ())
00471       && (-gear <= mp_drivetrain->transmission ()->reverse_gears ()))
00472   {
00473     m_shift_pending = true;
00474     m_shift_timer = 0.0;
00475     m_last_gear = mp_drivetrain->transmission ()->gear ();
00476     m_new_gear = gear;
00477   }
00478       
00479   return m_new_gear;
00480 }
00481 
00482 void Vamos_Body::
00483 Car::clutch (double factor, double time)
00484 {
00485   m_clutch_key_control.target (factor, time, 0.0);
00486 }
00487 
00488 // Engage the clutch with a time constant of TIME.
00489 void Vamos_Body::
00490 Car::engage_clutch (double time)
00491 {
00492   // Wait for the shift timer.
00493   double delay = m_shift_delay - m_shift_timer;
00494   m_clutch_key_control.target (1.0, time, delay);
00495 }
00496 
00497 // Disengage the clutch with a time constant of TIME.
00498 void Vamos_Body::
00499 Car::disengage_clutch (double time)
00500 {
00501   // Wait for the shift timer.
00502   double delay = m_shift_delay - m_shift_timer;
00503   m_clutch_key_control.target (0.0, time, delay);
00504 }
00505 
00506 // Return the pointer to the WHEEL_INDEXth wheel.
00507 Vamos_Body::Wheel* Vamos_Body::Car::
00508 wheel (int wheel_index) const
00509 {
00510   return m_wheels [wheel_index];
00511 }
00512 
00513 // Set the front brake bias to BIAS.
00514 void Vamos_Body::
00515 Car::brake_bias (double bias)
00516 {
00517   if ((bias >= 0.0) || (bias <= 1.0))
00518     {
00519       m_front_brake_bias = bias;
00520     }
00521 }
00522 
00523 // Return the position of the viewpont.
00524 Three_Vector Vamos_Body::
00525 Car::view_position () const
00526 {
00527   //return m_chassis.position () + m_chassis.rotate_out (m_driver_view);
00528         return m_driver_view;
00529 }
00530 
00531 void Vamos_Body::
00532 Car::start_engine ()
00533 {
00534   mp_drivetrain->engine ()->start ();
00535   m_clutch_key_control.end ();
00536 }
00537 
00538 // Restore the initial conditions and then set the position to
00539 // POSITION and the orientation to ORIENTATION.
00540 void Vamos_Body::Car::
00541 reset (const Three_Vector& position, const Three_Matrix& orientation)
00542 {
00543   m_chassis.reset (position, orientation);
00544   private_reset ();
00545 }
00546 
00547 // Restore the initial conditions.
00548 void Vamos_Body::Car::
00549 reset ()
00550 {
00551   m_chassis.reset ();
00552   private_reset ();
00553 }
00554 
00555 // Perform operations common to both reset() methods. 
00556 void Vamos_Body::Car::
00557 private_reset ()
00558 {
00559   mp_drivetrain->reset ();
00560   shift (0);
00561   start_engine ();
00562 }
00563 
00564 void Vamos_Body::
00565 Car::drivetrain (Drivetrain* drive)
00566 {
00567   assert (drive != 0);
00568   delete mp_drivetrain;
00569   mp_drivetrain = drive;
00570 }
00571 
00572 // Return true if the position is within the crash box.
00573 bool Vamos_Body::
00574 Car::collision (const Three_Vector& position) const
00575 {
00576   return m_crash_box.within (m_chassis.transform_in (position));
00577 }
00578 
00579 // Return true if the position is within the crash box.
00580 bool Vamos_Body::
00581 Car::Crash_Box::within (const Three_Vector& position) const
00582 {
00583   return (position [0] < front) && (position [0] > back)
00584     && (position [1] < left) && (position [1] > right)
00585     && (position [2] < top) && (position [2] > bottom);
00586 }
00587 
00588 //* Class Car_Reader
00589 
00590 //** Constructor
00591 /*
00592 Vamos_Body::
00593 Car_Reader::Car_Reader (std::string data_dir, 
00594                         std::string car_file, 
00595                         Vamos_Body::Car* car) 
00596   : m_first_model_for_this_wheel (true),
00597     m_data_dir (data_dir),
00598     mp_car (car),
00599     mp_tachometer (0),
00600     mp_speedometer (0),
00601     mp_fuel_gauge (0),
00602     mp_gear_indicator (0),
00603     mp_steering_wheel (0),
00604     m_tachometer_type ("dial"),
00605     m_speedometer_type ("dial"),
00606     m_fuel_gauge_type ("dial")
00607 {
00608   read (data_dir + car_file);
00609 }
00610 
00611 
00612 Vamos_Body::
00613 Car_Reader::~Car_Reader ()
00614 {
00615   for (std::vector <Model_Info*>::iterator it = m_models.begin ();
00616        it != m_models.end ();
00617        it++)
00618     {
00619       delete *it;
00620     }
00621 }
00622 
00623 
00624 void Vamos_Body::
00625 Car_Reader::on_start_tag (const Vamos_Geometry::XML_Tag& tag)
00626 {
00627   //  std::cout << "start " << tag.get_label () << std::endl;
00628   m_tag = tag.get_label ();
00629   m_path = m_path + '/' + m_tag;
00630 
00631   const Vamos_Geometry::XML_Tag::Attribute_List& 
00632     attribs = tag.get_attributes ();
00633 
00634   if ((m_path == "/car/exterior-model") || (m_path == "/car/interior-model"))
00635     {
00636       m_strings.clear ();
00637       m_strings.resize (2);
00638       m_doubles.resize (1);
00639       m_doubles [0] = 1.0;
00640       m_vectors.clear ();
00641       m_vectors.resize (2);
00642     }
00643   else if (m_tag == "view")
00644     {
00645       m_vectors.clear ();
00646       m_doubles.clear ();
00647       m_doubles.resize (4);
00648     }
00649   else if (m_tag == "mirror")
00650     {
00651       m_vectors.clear ();
00652       m_doubles.resize (6);
00653       m_strings.resize (1);
00654     }
00655   else if (m_tag == "steering")
00656     {
00657       m_doubles.clear ();
00658       m_doubles.resize (3);
00659     }
00660   else if (m_tag == "dashboard")
00661     {
00662       m_ints.clear ();
00663       m_ints.resize (1);
00664       m_doubles.clear ();
00665       m_doubles.resize (12);
00666       m_strings.clear ();
00667       m_strings.resize (2);
00668       m_bools.clear ();
00669       m_bools.resize (1);
00670       m_vectors.clear ();
00671       m_vectors.resize (1);
00672       m_points.clear ();
00673       ma_mirrors.clear ();
00674     }
00675   else if (m_tag == "on-steering-wheel")
00676     {
00677       m_bools [0] = true;
00678     }
00679   else if (m_tag == "tachometer")
00680     {
00681       if (attribs.size () == 0)
00682         {
00683           m_tachometer_type = "dial";
00684         }
00685       else
00686         {
00687           m_tachometer_type = attribs [0].value;
00688         }
00689     }
00690   else if (m_tag == "speedometer")
00691     {
00692       if (attribs.size () == 0)
00693         {
00694           m_speedometer_type = "dial";
00695         }
00696       else
00697         {
00698           m_speedometer_type = attribs [0].value;
00699         }
00700     }
00701   else if (m_tag == "fuel-gauge")
00702     {
00703       if (attribs.size () == 0)
00704         {
00705           m_fuel_gauge_type = "dial";
00706         }
00707       else
00708         {
00709           m_fuel_gauge_type = attribs [0].value;
00710         }
00711     }
00712   else if (m_tag == "engine")
00713     {
00714       m_doubles.clear ();
00715       m_doubles.resize (13);
00716       m_vectors.clear ();
00717       m_strings.clear ();
00718       m_strings.resize (1);
00719     }
00720         else if (m_tag == "torque-curve")
00721     {
00722       m_points.clear ();
00723       m_bools [0] = true;
00724       std::istringstream is (attribs [0].value.c_str ());
00725       is >> m_doubles [9];
00726     }
00727 
00728   else if (m_tag == "clutch")
00729     {
00730       m_doubles.clear ();
00731     }
00732   else if (m_tag == "transmission")
00733     {
00734       m_doubles.clear ();
00735       m_gears.clear ();
00736     }
00737   else if (m_tag == "differential")
00738     {
00739       m_doubles.clear ();
00740     }
00741   else if (m_tag == "fuel-tank")
00742     {
00743       m_doubles.clear ();
00744       m_vectors.clear ();
00745     }
00746   else if (m_tag == "contact-point")
00747     {
00748       m_doubles.resize (3);
00749       m_strings.resize (1);
00750       m_vectors.clear ();
00751     }
00752   else if (m_tag == "particle")
00753     {
00754       m_doubles.resize (1);
00755       m_vectors.clear ();
00756     }
00757   else if (m_tag == "drag")
00758     {
00759       m_doubles.resize (2);
00760       m_vectors.clear ();
00761     }
00762   else if (m_tag == "wing")
00763     {
00764       m_doubles.resize (6);
00765       m_vectors.clear ();
00766     }
00767   else if (m_tag == "wheel")
00768     {
00769       if (m_doubles.size () != 23)
00770         {
00771           m_doubles.resize (23);
00772           m_doubles [8] = 0.0;
00773           m_doubles [20] = 0.0;
00774           m_long_parameters.resize (11);
00775           m_trans_parameters.resize (15);
00776           m_align_parameters.resize (18);
00777           m_strings.resize (3);
00778           m_vectors.resize (5);
00779         }
00780       m_strings [0] = attribs [0].value;
00781       m_strings [1] = attribs [1].value;
00782       m_bools.clear ();
00783       m_bools.resize (2);
00784       m_first_model_for_this_wheel = true;
00785     }
00786   else if (m_tag == "steered")
00787     {
00788       m_bools [0] = true;
00789     }
00790   else if (m_tag == "driven")
00791     {
00792       m_bools [1] = true;
00793     }
00794 }
00795 
00796 void Vamos_Body::
00797 Car_Reader::on_end_tag (const Vamos_Geometry::XML_Tag& tag)
00798 {
00799   //  std::cout << "end " << tag.get_label () << std::endl;
00800   m_tag = tag.get_label ();
00801 
00802   if ((m_path == "/car/exterior-model") 
00803       && (m_strings [0] != ""))
00804     {
00805       mp_car->exterior_model ("cars/" + m_strings [0],
00806                               m_doubles [0], m_vectors [0], m_vectors [1]);
00807     }
00808   else if ((m_path == "/car/interior-model") 
00809            && (m_strings [0] != ""))
00810     {
00811       mp_car->interior_model (m_data_dir + "cars/" + m_strings [0],
00812                               m_doubles [0], m_vectors [0], m_vectors [1]);
00813     }
00814   else if (m_tag == "view")
00815     {
00816       mp_car->set_view (m_vectors [0], m_doubles [0], 
00817                         m_doubles [1], m_doubles [2], m_doubles [3]);
00818     }
00819   else if (m_tag == "mirror")
00820     {
00821       mp_car->add_rear_view (m_vectors [0], m_doubles [0], m_doubles [1],
00822                              m_doubles [2], m_doubles [3], 
00823                              m_doubles [4], m_doubles [5],
00824                              m_data_dir + "textures/" + m_strings [0]);
00825     }
00826   else if (m_tag == "steering")
00827     {
00828       mp_car->max_steer_angle (m_doubles [0]);
00829       //mp_car->max_steer_angle (60.0);
00830       mp_car->steer_exponent (m_doubles [1]);
00831       mp_car->steer_speed_sensitivity (m_doubles [2]);
00832     }
00833   else if (m_tag == "mirror-frame")
00834     {
00835       ma_mirrors.
00836         push_back (new Facade (m_doubles [0], m_doubles [1],
00837                                m_doubles [2], m_doubles [3],
00838                                m_doubles [4],
00839                                m_data_dir + "textures/" + m_strings [0]));
00840     }
00841   else if (m_tag == "tachometer")
00842     {
00843       if (m_tachometer_type == "LED")
00844         {
00845           mp_tachometer = 
00846             new LED_Gauge (m_doubles [0], m_doubles [1], m_doubles [2],
00847                            m_doubles [3], m_ints [0], 
00848                            m_doubles [4], m_doubles [5],
00849                            m_data_dir + "textures/" + m_strings [0],
00850                            m_bools [0]);
00851           m_bools [0] = false;
00852         }
00853       else if (m_tachometer_type == "digital")
00854         {
00855           mp_tachometer = 
00856             new Digital_Gauge (m_doubles [0], m_doubles [1],
00857                                m_doubles [2], m_doubles [3],
00858                                m_doubles [4], m_ints [0],
00859                                m_data_dir + "textures/" + m_strings [0], 
00860                                m_bools [0]);
00861           m_bools [0] = false;
00862         }
00863       else
00864         {
00865           mp_tachometer = new Dial (m_doubles [0], m_doubles [1],
00866                                     m_doubles [2], m_doubles [3],
00867                                     m_doubles [4], m_doubles [5],
00868                                     m_doubles [6], m_doubles [7],
00869                                     m_data_dir + "textures/" + m_strings [0], 
00870                                     m_data_dir + "textures/" + m_strings [1]);
00871         }
00872     }
00873   else if (m_tag == "speedometer")
00874     {
00875       if (m_speedometer_type == "digital")
00876         {
00877           mp_speedometer = 
00878             new Digital_Gauge (m_doubles [0], m_doubles [1],
00879                                m_doubles [2], m_doubles [3],
00880                                m_doubles [4], m_ints [0],
00881                                m_data_dir + "textures/" + m_strings [0], 
00882                                m_bools [0]);
00883           m_bools [0] = false;
00884         }
00885       else
00886         {
00887           mp_speedometer = new Dial (m_doubles [0], m_doubles [1],
00888                                      m_doubles [2], m_doubles [3],
00889                                      m_doubles [4], m_doubles [5],
00890                                      m_doubles [6], m_doubles [7],
00891                                      m_data_dir + "textures/" + m_strings [0], 
00892                                      m_data_dir + "textures/" + m_strings [1]);
00893         }
00894     }
00895   else if (m_tag == "fuel-gauge")
00896     {
00897       if (m_fuel_gauge_type == "digital")
00898         {
00899           mp_fuel_gauge = 
00900             new Digital_Gauge (m_doubles [0], m_doubles [1],
00901                                m_doubles [2], m_doubles [3],
00902                                m_doubles [4], m_ints [0],
00903                                m_data_dir + "textures/" + m_strings [0], 
00904                                m_bools [0]);
00905           m_bools [0] = false;
00906         }
00907       else
00908         {
00909           mp_fuel_gauge = new Dial (m_doubles [0], m_doubles [1],
00910                                     m_doubles [2], m_doubles [3],
00911                                     m_doubles [4], m_doubles [5],
00912                                     m_doubles [6], m_doubles [7],
00913                                     m_data_dir + "textures/" + m_strings [0], 
00914                                     m_data_dir + "textures/" + m_strings [1]);
00915         }
00916     }
00917   else if (m_tag == "gear-indicator")
00918     {
00919       mp_gear_indicator = 
00920         new Gear_Indicator (m_doubles [0], m_doubles [1],
00921                             m_doubles [2], m_doubles [3],
00922                             m_doubles [4], m_ints [0],
00923                             m_data_dir + "textures/" + m_strings [0],
00924                             m_bools [0]);
00925       m_bools [0] = false;
00926     }
00927   else if (m_tag == "gear-shift")
00928     {
00929       mp_gear_indicator = 
00930         new Gear_Shift (m_doubles [0], m_doubles [1],
00931                         m_doubles [2], m_doubles [3],
00932                         m_doubles [4], m_vectors [0],
00933                         m_points,
00934                         m_data_dir + "textures/" + m_strings [0],
00935                         m_data_dir + "textures/" + m_strings [1]);
00936     }
00937   else if (m_tag == "steering-wheel")
00938     {
00939       mp_steering_wheel = 
00940         new Steering_Wheel (m_doubles [0], m_doubles [1],
00941                             m_doubles [2], m_doubles [3],
00942                             m_doubles [4], m_doubles [5],
00943                             m_doubles [6], m_doubles [7],
00944                             m_data_dir + "textures/" + m_strings [0]);
00945     }
00946   else if (m_tag == "dashboard")
00947     {
00948       Dashboard* dash = new Dashboard (m_doubles [8], m_doubles [9],
00949                                        m_doubles [10], m_doubles [11]);
00950       for (std::vector <Facade*>::iterator it = ma_mirrors.begin ();
00951            it != ma_mirrors.end ();
00952            it++)
00953         {
00954           dash->add_facade (*it);
00955         }
00956       dash->add_tachometer (mp_tachometer);
00957       dash->add_speedometer (mp_speedometer);
00958       dash->add_fuel_gauge (mp_fuel_gauge);
00959       dash->add_gear_indicator (mp_gear_indicator);
00960       dash->add_steering_wheel (mp_steering_wheel);
00961       mp_car->dashboard (dash);
00962     }
00963   else if (m_path ==  "/car/dashboard/extras")
00964     {
00965       mp_car->show_dashboard_extras (true);
00966     }
00967   else if (m_tag == "engine")
00968     {
00969       mp_engine = new Engine (m_doubles [0], m_vectors [0], m_doubles [1], 
00970                               m_doubles [2], m_doubles [3], m_doubles [4], 
00971                               m_doubles [5], m_doubles [6], m_doubles [7],
00972                               m_doubles [8]);
00973 
00974                 if (m_bools [0])
00975         {
00976           mp_engine->set_torque_curve (m_points);
00977           mp_engine->set_friction (m_doubles [9]);
00978         }
00979 
00980       mp_car->engine_sound (m_data_dir + "sounds/" + m_strings [0], 
00981                             m_doubles [9], m_doubles [10],
00982                             m_doubles [11], m_doubles [12]);
00983     }
00984 
00985    else if (m_tag == "clutch")
00986     {
00987       if (m_doubles.size () != 4)
00988         {
00989           error ("clutch requires 4 arguments");
00990         }
00991       mp_clutch = new Clutch (m_doubles [0], m_doubles [1], m_doubles [2], 
00992                               m_doubles [3]);
00993     }
00994 
00995   else if (m_tag == "transmission")
00996     {
00997       if (m_doubles.size () == 4)
00998         {
00999           mp_transmission = new Transmission (int (m_doubles [0]),
01000                                               m_doubles [1],
01001                                               m_doubles [2]);
01002           mp_car->shift_delay (m_doubles [3]);
01003         }
01004       else
01005         {
01006           mp_transmission = new Transmission;
01007           for (std::vector <std::pair <int, double> >::const_iterator 
01008                  it = m_gears.begin ();
01009                it != m_gears.end ();
01010                it++)
01011             {
01012               mp_transmission->gear_ratio (it->first, it->second);
01013             } 
01014           mp_car->shift_delay (m_doubles [1]);
01015         }
01016     }
01017   
01018   else if (m_tag == "differential")
01019     {
01020       if (m_doubles.size () != 2)
01021         {
01022           error ("differential requires 2 arguments");
01023         }
01024       mp_differential = new Differential (m_doubles [0], m_doubles [1]);
01025     }
01026 
01027   else if (m_tag == "drivetrain")
01028     {
01029       delete mp_car->mp_drivetrain;
01030       mp_car->mp_drivetrain = 
01031         new Drivetrain (mp_engine, mp_clutch, 
01032                         mp_transmission, mp_differential);
01033     }
01034 
01035   else if (m_tag == "fuel-tank")
01036     {
01037       if ((m_doubles.size () != 3) || (m_vectors.size () != 1))
01038         {
01039           error ("fuel tank requires 1 or 3 elements");
01040         }
01041       delete mp_car->mp_fuel_tank;
01042       mp_car->mp_fuel_tank = new Fuel_Tank (m_vectors [0], m_doubles [0],
01043                                             m_doubles [1], m_doubles [2]);
01044     }
01045 
01046   else if (m_tag == "car")
01047     {
01048       mp_car->chassis ().particles ().
01049         push_back (mp_car->mp_drivetrain->engine ());
01050       mp_car->chassis ().particles ().push_back (mp_car->mp_fuel_tank);
01051     }
01052 
01053   else if (m_tag == "particle")
01054     {
01055       mp_car->chassis ().particles ().
01056         push_back (new Particle (m_doubles [0], m_vectors [0]));
01057     }
01058   else if (m_tag == "contact-point")
01059     {
01060       Material::Material_Type material = Material::UNKNOWN;
01061       if (m_strings [0] == "rubber")
01062         material = Material::RUBBER;
01063       else if (m_strings [0] == "metal")
01064         material = Material::METAL;
01065 
01066       mp_car->chassis ().particles ().
01067         push_back (new Contact_Point (m_doubles [0], m_vectors [0], material,
01068                                       m_doubles [1], m_doubles [2]));
01069     }
01070   else if (m_tag == "drag")
01071     {
01072       mp_car->chassis ().particles ().push_back (new Drag (m_vectors [0], 
01073                                                m_doubles [0], 
01074                                                m_doubles [1]));
01075     }
01076   else if (m_tag == "wing")
01077     {
01078       mp_car->chassis ().particles ().
01079         push_back (new Wing (m_vectors [0], m_doubles [0], 
01080                              m_doubles [1], m_doubles [2], 
01081                              m_doubles [3], m_doubles [4]));
01082     }
01083   else if (m_path == "/car/wheel/suspension/model")
01084     {
01085       if (m_first_model_for_this_wheel)
01086         {
01087           m_models.clear ();
01088           m_first_model_for_this_wheel = false;
01089         }
01090       m_models.push_back (new Model_Info (m_strings [2], m_doubles [21],
01091                                           m_vectors [3], m_vectors [4]));
01092     }
01093   else if (m_tag == "wheel")
01094     {
01095       Side side = (m_strings [0] == "left") ? LEFT : RIGHT;
01096       Suspension* suspension =
01097         new Suspension (m_vectors [1], m_vectors [2], side, m_doubles [0],
01098                         m_doubles [1], m_doubles [2], m_doubles [3],
01099                         m_doubles [4]);
01100       suspension->camber (m_doubles [5]);
01101       suspension->caster (m_doubles [6]);
01102       suspension->toe (m_doubles [7]);
01103       if (m_doubles [8] != 0.0)
01104         {
01105           Suspension* other = static_cast <Suspension*> 
01106             (*(mp_car->chassis ().particles ().end () - 2));
01107           assert (other != 0);
01108           suspension->anti_roll (other, m_doubles [8]);
01109           m_doubles [8] = 0.0;
01110         }
01111       for (std::vector <Model_Info*>::iterator it = m_models.begin ();
01112            it != m_models.end ();
01113            it++)
01114         {
01115           suspension->set_model ("cars/" + (*it)->file,
01116                                  (*it)->scale, 
01117                                  (*it)->translate,
01118                                  (*it)->rotate);
01119         }
01120       mp_car->chassis ().particles ().push_back (suspension->hinge ());
01121       mp_car->chassis ().particles ().push_back (suspension);
01122 
01123       Tire_Friction friction (m_long_parameters, m_trans_parameters,
01124                               m_align_parameters);
01125       Tire tire (m_doubles [9], m_doubles [10], m_doubles [11], friction,
01126                  m_doubles [12]);
01127 
01128       double bias = m_doubles [17];
01129       if (m_strings [1] == "rear")
01130           bias = 1.0 - bias;
01131       Brake brake (m_doubles [13], m_doubles [14], m_doubles [15], 
01132                    m_doubles [16], bias);
01133  
01134       Wheel* wheel = new Wheel (m_doubles [18], m_vectors [0], 
01135                                 m_doubles [22], m_doubles [20], m_doubles [19],
01136                                 suspension, tire, brake,
01137                                 m_bools [0], m_bools [1], side);
01138       mp_car->chassis ().particles ().push_back (wheel);
01139       mp_car->m_wheels.push_back (wheel);
01140       if (m_slow_model != "")
01141         {
01142           std::string stator_path;
01143           if (m_stator_model != "")
01144             {
01145               stator_path = m_data_dir + "cars/" + m_stator_model;
01146             }
01147                 if (m_strings [1] == "rear")
01148                         {
01149           wheel->set_models (settings.GetFullDataPath("cars/" + mp_car->m_car_file + "/wheel_rear.joe"),
01150                              settings.GetFullDataPath("cars/" + mp_car->m_car_file + "/wheel_rear.joe"),
01151                              m_transition,
01152                              stator_path, m_stator_offset, 
01153                              m_scale, m_translation, m_rotation);
01154                         }
01155                         else
01156                         {
01157                                 wheel->set_models (settings.GetFullDataPath("cars/" + mp_car->m_car_file + "/wheel_front.joe"),
01158                              settings.GetFullDataPath("cars/" + mp_car->m_car_file + "/wheel_front.joe"),
01159                              m_transition,
01160                              stator_path, m_stator_offset, 
01161                              m_scale, m_translation, m_rotation);
01162                         }
01163         }
01164     }
01165 
01166   m_path = m_path.substr (0, m_path.find_last_of ("/"));
01167 }
01168 
01169 void Vamos_Body::
01170 Car_Reader::on_data (std::string data_string)
01171 {
01172   std::string data = remove_leading_space (data_string);
01173   if (data.size () == 0)
01174     {
01175       return;
01176     }
01177   std::istringstream is (data.c_str ());
01178 
01179   if (m_path == "/car/dashboard/position")
01180     {
01181       char delim;
01182       is >> delim >> m_doubles [8] >> delim >> m_doubles [9] 
01183          >> delim >> m_doubles [10];
01184     }
01185   else if (m_path == "/car/dashboard/tilt")
01186     {
01187       is >> m_doubles [11];
01188     }
01189   else if ((m_path == "/car/dashboard/mirror-frame/position")
01190            || (m_path == "/car/dashboard/tachometer/position")
01191            || (m_path == "/car/dashboard/speedometer/position")
01192            || (m_path == "/car/dashboard/fuel-gauge/position")
01193            || (m_path == "/car/dashboard/gear-indicator/position")
01194            || (m_path == "/car/dashboard/gear-shift/position")
01195            || (m_path == "/car/dashboard/steering-wheel/position"))
01196     {
01197       char delim;
01198       is >> delim >> m_doubles [0] >> delim >> m_doubles [1] 
01199          >> delim >> m_doubles [2];
01200     }
01201   else if ((m_path == "/car/dashboard/tachometer/radius")
01202            || (m_path == "/car/dashboard/tachometer/width")
01203            || (m_path == "/car/dashboard/speedometer/radius")
01204            || (m_path == "/car/dashboard/fuel-gauge/radius")
01205            || (m_path == "/car/dashboard/steering-wheel/radius"))
01206     {
01207       is >> m_doubles [3];
01208     }
01209   else if (m_path == "/car/dashboard/tachometer/elements")
01210     {
01211       is >> m_ints [0];
01212     }
01213   else if (m_path == "/car/dashboard/tachometer/range")
01214     {
01215       char delim;
01216       is >> delim >> m_doubles [4] >> delim >> m_doubles [5];
01217     }
01218   else if ((m_path == "/car/dashboard/tachometer/min")
01219            || (m_path == "/car/dashboard/speedometer/min")
01220            || (m_path == "/car/dashboard/fuel-gauge/min")
01221            || (m_path == "/car/dashboard/steering-wheel/min"))
01222     {
01223       char delim;
01224       is >> delim >> m_doubles [4] >> delim >> m_doubles [5];
01225     }
01226   else if ((m_path == "/car/dashboard/tachometer/max")
01227            || (m_path == "/car/dashboard/speedometer/max")
01228            || (m_path == "/car/dashboard/fuel-gauge/max")
01229            || (m_path == "/car/dashboard/steering-wheel/max"))
01230     {
01231       char delim;
01232       is >> delim >> m_doubles [6] >> delim >> m_doubles [7];
01233     }
01234   else if (m_path == "/car/dashboard/gear-shift/rotation")
01235     {
01236       is >> m_vectors [0];
01237     }
01238   else if (m_path == "/car/dashboard/gear-shift/stick-positions")
01239     {
01240       Two_Point point;
01241       while (is >> point)
01242         {
01243           m_points.push_back (point);
01244         }
01245     }
01246   else if ((m_path == "/car/dashboard/mirror-frame/image")
01247            || (m_path == "/car/dashboard/tachometer/face")
01248            || (m_path == "/car/dashboard/tachometer/image")
01249            || (m_path == "/car/dashboard/speedometer/face")
01250            || (m_path == "/car/dashboard/speedometer/image")
01251            || (m_path == "/car/dashboard/fuel-gauge/face")
01252            || (m_path == "/car/dashboard/fuel-gauge/image")
01253            || (m_path == "/car/dashboard/gear-indicator/image")
01254            || (m_path == "/car/dashboard/gear-shift/gate")
01255            || (m_path == "/car/dashboard/steering-wheel/image"))
01256     {
01257       is >> m_strings [0];
01258     }
01259   else if ((m_path == "/car/dashboard/tachometer/needle")
01260            || (m_path == "/car/dashboard/speedometer/needle")
01261            || (m_path == "/car/dashboard/fuel-gauge/needle")
01262            || (m_path == "/car/dashboard/gear-shift/stick"))
01263     {
01264       is >> m_strings [1];
01265     }
01266   else if ((m_path == "/car/dashboard/mirror-frame/size")
01267            || (m_path == "/car/dashboard/gear-indicator/size")
01268            || (m_path == "/car/dashboard/gear-shift/size")
01269            || (m_path == "/car/dashboard/tachometer/size")
01270            || (m_path == "/car/dashboard/speedometer/size")
01271            || (m_path == "/car/dashboard/fuel-gauge/size"))
01272     {
01273       char delim;
01274       is >> delim >> m_doubles [3] >> delim >> m_doubles [4];
01275     }
01276   else if ((m_path == "/car/dashboard/gear-indicator/numbers")
01277            || (m_path == "/car/dashboard/tachometer/places")
01278            || (m_path == "/car/dashboard/speedometer/places")
01279            || (m_path == "/car/dashboard/fuel-gauge/places"))
01280     {
01281       is >> m_ints [0];
01282     }
01283 
01284   // Particle
01285   else if (m_path == "/car/particle/mass")
01286     is >> m_doubles [0];
01287 
01288   // Contact Point
01289   else if (m_path == "/car/contact-point/mass")
01290     is >> m_doubles [0];
01291   else if (m_path == "/car/contact-point/material")
01292     is >> m_strings [0];
01293   else if (m_path == "/car/contact-point/friction")
01294     is >> m_doubles [1];
01295   else if (m_path == "/car/contact-point/restitution")
01296     is >> m_doubles [2];
01297 
01298   // Drag
01299   else if (m_path == "/car/drag/frontal-area")
01300     is >> m_doubles [0];
01301   else if (m_path == "/car/drag/drag-coefficient")
01302     is >> m_doubles [1];
01303 
01304   // Wing
01305   else if (m_path == "/car/wing/frontal-area")
01306     is >> m_doubles [0];
01307   else if (m_path == "/car/wing/drag-coefficient")
01308     is >> m_doubles [1];
01309   else if (m_path == "/car/wing/surface-area")
01310     is >> m_doubles [2];