00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include "physics/vehicle.hpp"
00035 #include "physics/vehicle_module.hpp"
00036
00037 #include "data/broker.hpp"
00038 #include "math/vector.hpp"
00039 #include "math/transform.hpp"
00040 #include "math/quaternion.hpp"
00041 #include "scenegraph/utils.hpp"
00042 #include "platform/vbuffer.hpp"
00043
00044 namespace gsgl
00045 {
00046 using namespace data;
00047 using namespace math;
00048 using namespace scenegraph;
00049 using namespace platform;
00050
00051 namespace physics
00052 {
00053
00054 static int num_vehicles = 0;
00055
00056
00057 vehicle::vehicle(const config_record & obj_config)
00058 : rigid_body(obj_config)
00059 {
00060 get_name() = string::format(L"vehicle_%d (%ls)", num_vehicles++, get_name().w_string());
00061
00062 for (list<config_record>::const_iterator i = obj_config.get_children().iter(); i.is_valid(); ++i)
00063 {
00064 if (i->get_name() == L"module")
00065 {
00066 string fname = (*i)[L"file"];
00067 if (fname.is_empty())
00068 throw runtime_exception(L"%ls: vehicle module withfile name.", i->get_file().get_full_path().w_string());
00069
00070 config_record vm_rec(obj_config.get_directory().get_full_path() + fname);
00071 string classname = vm_rec.get_name();
00072 if (classname.is_empty())
00073 throw runtime_exception(L"%ls: vehicle module withclass name.", fname.w_string());
00074
00075 vehicle_module *vm = dynamic_cast<vehicle_module *>(broker::global_instance()->create_object(classname, vm_rec));
00076 assert(vm);
00077
00078 vm->get_name() = string::format(L"%ls: %ls", get_name().w_string(), vm->get_name().w_string());
00079 modules.append(vm);
00080 add_child(vm);
00081
00082 string pos_str = (*i)[L"position"];
00083 if (!pos_str.is_empty())
00084 vm->get_translation() = vector(pos_str);
00085
00086 string qrot_str = (*i)[L"qrotation"];
00087 if (!qrot_str.is_empty())
00088 vm->get_orientation() = transform(quaternion(qrot_str));
00089 }
00090 }
00091 }
00092
00093
00094 vehicle::~vehicle()
00095 {
00096 }
00097
00098
00099
00100
00101 gsgl::real_t vehicle::get_priority(gsgl::scenegraph::context *)
00102 {
00103 return node::NODE_DRAW_IGNORE;
00104 }
00105
00106
00107 gsgl::real_t vehicle::default_view_distance() const
00108 {
00109 return minimum_view_distance() * 2.0f;
00110 }
00111
00112
00113 gsgl::real_t vehicle::minimum_view_distance() const
00114 {
00115 return utils::greatest_extent(this);
00116 }
00117
00118
00119 void vehicle::init(gsgl::scenegraph::context *c)
00120 {
00121 rigid_body::init(c);
00122 }
00123
00124
00125 void vehicle::draw(gsgl::scenegraph::context *c)
00126 {
00127 rigid_body::draw(c);
00128 }
00129
00130
00131 void vehicle::update(gsgl::scenegraph::context *c)
00132 {
00133 rigid_body::update(c);
00134 }
00135
00136
00137 void vehicle::cleanup(gsgl::scenegraph::context *c)
00138 {
00139 rigid_body::cleanup(c);
00140 }
00141
00142
00143 static void calculate_inertia_subexpressions(gsgl::real_t w0, gsgl::real_t w1, gsgl::real_t w2,
00144 gsgl::real_t & f1, gsgl::real_t & f2, gsgl::real_t & f3,
00145 gsgl::real_t & g0, gsgl::real_t & g1, gsgl::real_t & g2)
00146 {
00147 gsgl::real_t temp0 = w0 + w1;
00148 f1 = temp0 + w2;
00149 gsgl::real_t temp1 = w0 * w0;
00150 gsgl::real_t temp2 = temp1 + w1 * temp0;
00151 f2 = temp2 + w2 * f1;
00152 f3 = w0 * temp1 + w1 * temp2 + w2 * f2;
00153 g0 = f2 + w0 * (f1 + w0);
00154 g1 = f2 + w1 * (f1 + w1);
00155 g2 = f2 + w2 * (f1 + w2);
00156 }
00157
00158
00159 transform vehicle::calculate_inertia_tensor(gsgl::math::vector & center_of_mass)
00160 {
00161 transform ibody;
00162
00163
00164 simple_array<gsgl::real_t> triangles;
00165 gsgl::real_t total_mass = 0;
00166
00167 for (simple_array<vehicle_module *>::iterator i = modules.iter(); i.is_valid(); ++i)
00168 {
00169 total_mass += (*i)->get_module_mass();
00170
00171 for (simple_array<model *>::const_iterator j = (*i)->get_models().iter(); j.is_valid(); ++j)
00172 {
00173 for (list<vertex_buffer *>::iterator k = (*j)->get_inertial_triangles().iter(); k.is_valid(); ++k)
00174 {
00175 triangles.append((*k)->get_buffer());
00176 }
00177 }
00178 }
00179
00180
00181 if ((triangles.size() % 9) != 0)
00182 throw internal_exception(__FILE__, __LINE__, L"vertices for inertia tensor calculation are not divisible by 9");
00183
00184 if (total_mass <= 0)
00185 throw runtime_exception(L"Vehicle %ls has a zero or negative total mass!", get_name().w_string());
00186
00187 mass = total_mass;
00188
00189
00190 int num = triangles.size() / 9;
00191 gsgl::real_t integral[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
00192 gsgl::real_t polyhedron_mass = 0;
00193
00194 for (int i = 0; i < num; ++i)
00195 {
00196
00197 gsgl::real_t x0 = triangles[i*9 + 0];
00198 gsgl::real_t y0 = triangles[i*9 + 1];
00199 gsgl::real_t z0 = triangles[i*9 + 2];
00200
00201 gsgl::real_t x1 = triangles[i*9 + 3];
00202 gsgl::real_t y1 = triangles[i*9 + 4];
00203 gsgl::real_t z1 = triangles[i*9 + 5];
00204
00205 gsgl::real_t x2 = triangles[i*9 + 6];
00206 gsgl::real_t y2 = triangles[i*9 + 7];
00207 gsgl::real_t z2 = triangles[i*9 + 8];
00208
00209
00210 gsgl::real_t a1 = x1 - x0;
00211 gsgl::real_t b1 = y1 - y0;
00212 gsgl::real_t c1 = z1 - z0;
00213
00214 gsgl::real_t a2 = x2 - x0;
00215 gsgl::real_t b2 = y2 - y0;
00216 gsgl::real_t c2 = z2 - z0;
00217
00218 gsgl::real_t d0 = b1*c2 - b2*c1;
00219 gsgl::real_t d1 = a2*c1 - a1*c2;
00220 gsgl::real_t d2 = a1*b2 - a2*b1;
00221
00222 gsgl::real_t f1x, f1y, f1z;
00223 gsgl::real_t f2x, f2y, f2z;
00224 gsgl::real_t f3x, f3y, f3z;
00225
00226 gsgl::real_t g0x, g0y, g0z;
00227 gsgl::real_t g1x, g1y, g1z;
00228 gsgl::real_t g2x, g2y, g2z;
00229
00230 calculate_inertia_subexpressions(x0, x1, x2, f1x, f2x, f3x, g0x, g1x, g2x);
00231 calculate_inertia_subexpressions(y0, y1, y2, f1y, f2y, f3y, g0y, g1y, g2y);
00232 calculate_inertia_subexpressions(z0, z1, z2, f1z, f2z, f3z, g0z, g1z, g2z);
00233
00234
00235 integral[0] += d0 * f1x;
00236 integral[1] += d0 * f2x;
00237 integral[2] += d1 * f2y;
00238 integral[3] += d2 * f2z;
00239 integral[4] += d0 * f3x;
00240 integral[5] += d1 * f3y;
00241 integral[6] += d2 * f3z;
00242 integral[7] += d0 * (y0*g0x + y1*g1x + y2*g2x);
00243 integral[8] += d1 * (z0*g0y + z1*g1y + z2*g2y);
00244 integral[9] += d2 * (x0*g0z + x1*g1z + x2*g2z);
00245 }
00246
00247 integral[0] /= 6.0;
00248 integral[1] /= 24.0;
00249 integral[2] /= 24.0;
00250 integral[3] /= 24.0;
00251 integral[4] /= 60.0;
00252 integral[5] /= 60.0;
00253 integral[6] /= 60.0;
00254 integral[7] /= 120.0;
00255 integral[8] /= 120.0;
00256 integral[9] /= 120.0;
00257
00258 polyhedron_mass = integral[0];
00259
00260 center_of_mass.get_x() = integral[1] / polyhedron_mass;
00261 center_of_mass.get_y() = integral[2] / polyhedron_mass;
00262 center_of_mass.get_z() = integral[3] / polyhedron_mass;
00263
00264
00265 ibody = transform::IDENTITY;
00266
00267 ibody[0] = integral[5] + integral[6];
00268 ibody[5] = integral[4] + integral[6];
00269 ibody[10] = integral[4] + integral[5];
00270
00271 ibody[1] = -integral[7];
00272 ibody[6] = -integral[8];
00273 ibody[2] = -integral[9];
00274
00275
00276 ibody[0] -= polyhedron_mass * (center_of_mass.get_y() * center_of_mass.get_y() + center_of_mass.get_z() * center_of_mass.get_z());
00277 ibody[5] -= polyhedron_mass * (center_of_mass.get_z() * center_of_mass.get_z() + center_of_mass.get_x() * center_of_mass.get_x());
00278 ibody[10] -= polyhedron_mass * (center_of_mass.get_x() * center_of_mass.get_x() + center_of_mass.get_y() * center_of_mass.get_y());
00279
00280 ibody[1] += polyhedron_mass * center_of_mass.get_x() * center_of_mass.get_y();
00281 ibody[6] += polyhedron_mass * center_of_mass.get_y() * center_of_mass.get_z();
00282 ibody[2] += polyhedron_mass * center_of_mass.get_z() * center_of_mass.get_x();
00283
00284
00285 gsgl::real_t mass_ratio = total_mass / polyhedron_mass;
00286 ibody[0] *= mass_ratio;
00287 ibody[5] *= mass_ratio;
00288 ibody[10] *= mass_ratio;
00289 ibody[1] *= mass_ratio;
00290 ibody[6] *= mass_ratio;
00291 ibody[2] *= mass_ratio;
00292
00293
00294 return ibody;
00295 }
00296
00297
00298 }
00299
00300 }