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 #include <physics/MassProperties>
00026 #include <physics/Material>
00027 #include <gfx/TriangleContainer>
00028 #include <gfx/TriangleIterator>
00029 #include <gfx/Triangle3>
00030
00031 using physics::MassProperties;
00032 using physics::Material;
00033 using gfx::TriangleContainer;
00034 using gfx::TriangleIterator;
00035 using gfx::Triangle3;
00036
00037
00038
00039 MassProperties::MassProperties()
00040 : mass(1.0), centerOfMass(0,0,0)
00041 {
00042 }
00043
00044 MassProperties::MassProperties(const TriangleContainer& triangles, ref<const Material> material)
00045 {
00046 computeMassProperties(triangles, material);
00047 }
00048
00049 void MassProperties::setIbody(const Matrix3& Ibody)
00050 {
00051 _Ibody = Ibody;
00052 try {
00053 _IbodyInv = base::inverse(Ibody);
00054 } catch (std::invalid_argument& e) {
00055 Logln("Warning: Invalid Inertia matrix (body frame) - cannot be inverted. Setting to identity.");
00056 _Ibody.setIdentity();
00057 _IbodyInv.setIdentity();
00058 }
00059 }
00060
00061 class MassProperties::VolData {
00062 public:
00063 SInt A,B,C;
00064 Real P1, Pa, Pb, Paa, Pab, Pbb, Paaa, Paab, Pabb, Pbbb;
00065 Real Fa, Fb, Fc, Faa, Fbb, Fcc, Faaa, Fbbb, Fccc, Faab, Fbbc, Fcca;
00066
00067 Real T0;
00068 Real T1[4];
00069 Real T2[4];
00070 Real TP[4];
00071 };
00072
00073
00074 class MassProperties::WTriangle : public gfx::Triangle3
00075 {
00076 public:
00077 WTriangle() { compNorm(); compW(); }
00078 WTriangle(const gfx::Triangle3& t) : gfx::Triangle3(t) { compNorm(); compW(); }
00079 WTriangle(const WTriangle& t) : gfx::Triangle3(t), norm(t.norm), w(t.w) {}
00080 virtual ~WTriangle() {}
00081
00082 void compNorm() { norm=normal(); }
00083 void compW() { w = -norm.x*_p1.x - norm.y*_p1.y - norm.z*_p1.z; }
00084
00085 Vector3 norm;
00086 Real w;
00087 };
00088
00089
00090
00091 void MassProperties::computeMassProperties(const TriangleContainer& triangles, ref<const Material> material)
00092 {
00093 Int X=1, Y=2, Z=3;
00094
00095 Matrix3 J;
00096 Point3 r;
00097
00098 VolData v;
00099 compVolumeIntegrals(triangles, v);
00100
00101 Real density = material->density();
00102
00103 if ( Math::isNAN(v.T0) || Math::equals(v.T0,0) ) {
00104 Logln("Warning: Mass property calculation failed. Setting inertia matrix to identity, mass to 1*density and center of mass to 0");
00105 _Ibody.setIdentity();
00106 _IbodyInv.setIdentity();
00107 mass = density * 1.0;
00108 centerOfMass = Point3(0,0,0);
00109 }
00110 else {
00111 mass = density * v.T0;
00112
00113
00114 r.x = v.T1[X]/v.T0;
00115 r.y = v.T1[Y]/v.T0;
00116 r.z = v.T1[Z]/v.T0;
00117
00118
00119 J.e(1,1) = density * (v.T2[Y] + v.T2[Z]);
00120 J.e(2,2) = density * (v.T2[Z] + v.T2[X]);
00121 J.e(3,3) = density * (v.T2[X] + v.T2[Y]);
00122 J.e(1,2) = J.e(2,1) = - density * v.TP[X];
00123 J.e(2,3) = J.e(3,2) = - density * v.TP[Y];
00124 J.e(3,1) = J.e(1,3) = - density * v.TP[Z];
00125
00126
00127 J.e(1,1) -= mass * (r.y*r.y + r.z*r.z);
00128 J.e(2,2) -= mass * (r.z*r.z + r.x*r.x);
00129 J.e(3,3) -= mass * (r.x*r.x + r.y*r.y);
00130 J.e(1,2) = J.e(2,1) += mass * r.x * r.y;
00131 J.e(2,3) = J.e(3,2) += mass * r.y * r.z;
00132 J.e(3,1) = J.e(1,3) += mass * r.z * r.x;
00133
00134 _Ibody = J;
00135 try {
00136 _IbodyInv = base::inverse(_Ibody);
00137 } catch (std::invalid_argument& e) {
00138 Logln("Warning: Inertia matrix (body frame) cannot be inverted - setting to identity");
00139 _Ibody.setIdentity();
00140 _IbodyInv.setIdentity();
00141 }
00142
00143 centerOfMass = r;
00144
00145 if (!centerOfMass.equals(Point3(0,0,0))) {
00146 Logln("Warning: Center of mass is not at coordinate origin - it is " << centerOfMass << ".");
00147 }
00148
00149 }
00150
00151 }
00152
00153
00154 void MassProperties::compVolumeIntegrals(const TriangleContainer& triangles, VolData& v)
00155 {
00156 SInt X=1, Y=2, Z=3;
00157
00158 TriangleContainer::const_iterator tris = triangles.begin();
00159 TriangleContainer::const_iterator endtris = triangles.end();
00160
00161 Real nx, ny, nz;
00162
00163 v.T0 = 0;
00164 v.T1[X] = v.T1[Y] = v.T1[Z] = 0;
00165 v.T2[X] = v.T2[Y] = v.T2[Z] = 0.0;
00166 v.TP[X] = v.TP[Y] = v.TP[Z] = 0.0;
00167
00168 while (tris != endtris) {
00169
00170 WTriangle f(*tris);
00171
00172 nx = base::abs(f.norm.x);
00173 ny = base::abs(f.norm.y);
00174 nz = base::abs(f.norm.z);
00175 if (nx > ny && nx > nz)
00176 v.C = X;
00177 else
00178 v.C = (ny > nz) ? Y : Z;
00179 v.A = ((v.C + 1 -1)%3)+1;
00180 v.B = ((v.A + 1 -1)%3)+1;
00181
00182 compFaceIntegrals(f,v);
00183
00184 v.T0 += f.norm.x * ((v.A == X) ? v.Fa : ((v.B == X) ? v.Fb : v.Fc));
00185
00186 v.T1[v.A] += f.norm[v.A] * v.Faa;
00187 v.T1[v.B] += f.norm[v.B] * v.Fbb;
00188 v.T1[v.C] += f.norm[v.C] * v.Fcc;
00189 v.T2[v.A] += f.norm[v.A] * v.Faaa;
00190 v.T2[v.B] += f.norm[v.B] * v.Fbbb;
00191 v.T2[v.C] += f.norm[v.C] * v.Fccc;
00192 v.TP[v.A] += f.norm[v.A] * v.Faab;
00193 v.TP[v.B] += f.norm[v.B] * v.Fbbc;
00194 v.TP[v.C] += f.norm[v.C] * v.Fcca;
00195
00196 ++tris;
00197 }
00198
00199 v.T1[X] /= 2.0; v.T1[Y] /= 2.0; v.T1[Z] /= 2.0;
00200 v.T2[X] /= 3.0; v.T2[Y] /= 3.0; v.T2[Z] /= 3.0;
00201 v.TP[X] /= 2.0; v.TP[Y] /= 2.0; v.TP[Z] /= 2.0;
00202
00203 }
00204
00205 void MassProperties::compFaceIntegrals(const WTriangle& t, VolData& v)
00206 {
00207 Real w;
00208 Real k1, k2, k3, k4;
00209
00210 compProjectionIntegrals(t,v);
00211
00212 w = t.w;
00213 k1 = 1 / t.norm[v.C]; k2 = k1 * k1; k3 = k2 * k1; k4 = k3 * k1;
00214
00215 v.Fa = k1 * v.Pa;
00216 v.Fb = k1 * v.Pb;
00217 v.Fc = -k2 * (t.norm[v.A]*v.Pa + t.norm[v.B]*v.Pb + w*v.P1);
00218
00219 v.Faa = k1 * v.Paa;
00220 v.Fbb = k1 * v.Pbb;
00221 v.Fcc = k3 * (Math::sqr(t.norm[v.A])*v.Paa + 2*t.norm[v.A]*t.norm[v.B]*v.Pab + Math::sqr(t.norm[v.B])*v.Pbb
00222 + w*(2*(t.norm[v.A]*v.Pa + t.norm[v.B]*v.Pb) + w*v.P1));
00223
00224 v.Faaa = k1 * v.Paaa;
00225 v.Fbbb = k1 * v.Pbbb;
00226 v.Fccc = -k4 * (Math::cube(t.norm[v.A])*v.Paaa + 3*Math::sqr(t.norm[v.A])*t.norm[v.B]*v.Paab
00227 + 3*t.norm[v.A]*Math::sqr(t.norm[v.B])*v.Pabb + Math::cube(t.norm[v.B])*v.Pbbb
00228 + 3*w*(Math::sqr(t.norm[v.A])*v.Paa + 2*t.norm[v.A]*t.norm[v.B]*v.Pab + Math::sqr(t.norm[v.B])*v.Pbb)
00229 + w*w*(3*(t.norm[v.A]*v.Pa + t.norm[v.B]*v.Pb) + w*v.P1));
00230
00231 v.Faab = k1 * v.Paab;
00232 v.Fbbc = -k2 * (t.norm[v.A]*v.Pabb + t.norm[v.B]*v.Pbbb + w*v.Pbb);
00233 v.Fcca = k3 * (Math::sqr(t.norm[v.A])*v.Paaa + 2*t.norm[v.A]*t.norm[v.B]*v.Paab + Math::sqr(t.norm[v.B])*v.Pabb
00234 + w*(2*(t.norm[v.A]*v.Paa + t.norm[v.B]*v.Pab) + w*v.Pa));
00235 }
00236
00237
00238 void MassProperties::compProjectionIntegrals(const WTriangle& t, VolData& v)
00239 {
00240 Real a0, a1, da;
00241 Real b0, b1, db;
00242 Real a0_2, a0_3, a0_4, b0_2, b0_3, b0_4;
00243 Real a1_2, a1_3, b1_2, b1_3;
00244 Real C1, Ca, Caa, Caaa, Cb, Cbb, Cbbb;
00245 Real Cab, Kab, Caab, Kaab, Cabb, Kabb;
00246
00247 v.P1 = v.Pa = v.Pb = v.Paa = v.Pab = v.Pbb = v.Paaa = v.Paab = v.Pabb = v.Pbbb = 0.0;
00248
00249 for (int i = 1; i <= 3; i++) {
00250 a0 = t(i)[v.A];
00251 b0 = t(i)[v.B];
00252 a1 = t(((i+1-1)%3)+1)[v.A];
00253 b1 = t(((i+1-1)%3)+1)[v.B];
00254 da = a1 - a0;
00255 db = b1 - b0;
00256 a0_2 = a0 * a0; a0_3 = a0_2 * a0; a0_4 = a0_3 * a0;
00257 b0_2 = b0 * b0; b0_3 = b0_2 * b0; b0_4 = b0_3 * b0;
00258 a1_2 = a1 * a1; a1_3 = a1_2 * a1;
00259 b1_2 = b1 * b1; b1_3 = b1_2 * b1;
00260
00261 C1 = a1 + a0;
00262 Ca = a1*C1 + a0_2; Caa = a1*Ca + a0_3; Caaa = a1*Caa + a0_4;
00263 Cb = b1*(b1 + b0) + b0_2; Cbb = b1*Cb + b0_3; Cbbb = b1*Cbb + b0_4;
00264 Cab = 3*a1_2 + 2*a1*a0 + a0_2; Kab = a1_2 + 2*a1*a0 + 3*a0_2;
00265 Caab = a0*Cab + 4*a1_3; Kaab = a1*Kab + 4*a0_3;
00266 Cabb = 4*b1_3 + 3*b1_2*b0 + 2*b1*b0_2 + b0_3;
00267 Kabb = b1_3 + 2*b1_2*b0 + 3*b1*b0_2 + 4*b0_3;
00268
00269 v.P1 += db*C1;
00270 v.Pa += db*Ca;
00271 v.Paa += db*Caa;
00272 v.Paaa += db*Caaa;
00273 v.Pb += da*Cb;
00274 v.Pbb += da*Cbb;
00275 v.Pbbb += da*Cbbb;
00276 v.Pab += db*(b1*Cab + b0*Kab);
00277 v.Paab += db*(b1*Caab + b0*Kaab);
00278 v.Pabb += da*(a1*Cabb + a0*Kabb);
00279 }
00280
00281 v.P1 /= 2.0;
00282 v.Pa /= 6.0;
00283 v.Paa /= 12.0;
00284 v.Paaa /= 20.0;
00285 v.Pb /= -6.0;
00286 v.Pbb /= -12.0;
00287 v.Pbbb /= -20.0;
00288 v.Pab /= 24.0;
00289 v.Paab /= 60.0;
00290 v.Pabb /= -60.0;
00291 }
00292
00293
00294 std::ostream& physics::operator<<(std::ostream& out, const MassProperties& mp)
00295 {
00296 return out << "Ibody:" << mp.Ibody() << std::endl
00297 << "mass:" << mp.mass << std::endl
00298 << "centerOfMass:" << mp.centerOfMass << std::endl;
00299 }