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];