Program Listing for File VolumeIntegration.cpp
↰ Return to documentation for file (Utils/VolumeIntegration.cpp)
#include "VolumeIntegration.h"
#include <stdio.h>
using namespace std;
using namespace Eigen;
using namespace Utilities;
#define SQR(x) ((x)*(x))
#define CUBE(x) ((x)*(x)*(x))
VolumeIntegration::VolumeIntegration(const unsigned int nVertices, const unsigned int nFaces, Vector3r * const vertices, const unsigned int* indices)
: m_nVertices(nVertices), m_nFaces(nFaces), m_indices(indices), m_face_normals(nFaces), m_weights(nFaces)
{
// compute center of mass
m_x.setZero();
for (unsigned int i(0); i < m_nVertices; ++i)
m_x += vertices[i];
m_x /= (Real)m_nVertices;
m_vertices.resize(nVertices);
for (unsigned int i(0); i < m_nVertices; ++i)
m_vertices[i] = vertices[i] - m_x;
for (unsigned int i(0); i < m_nFaces; ++i)
{
const Vector3r &a = m_vertices[m_indices[3 * i]];
const Vector3r &b = m_vertices[m_indices[3 * i + 1]];
const Vector3r &c = m_vertices[m_indices[3 * i + 2]];
const Vector3r d1 = b - a;
const Vector3r d2 = c - a;
m_face_normals[i] = d1.cross(d2);
if (m_face_normals[i].isZero(1.e-10))
m_face_normals[i].setZero();
else
m_face_normals[i].normalize();
m_weights[i] = -m_face_normals[i].dot(a);
}
}
void VolumeIntegration::compute_inertia_tensor(Real density)
{
volume_integrals();
m_volume = static_cast<Real>(T0);
m_mass = static_cast<Real>(density * T0);
/* compute center of mass */
m_r[0] = static_cast<Real>(T1[0] / T0);
m_r[1] = static_cast<Real>(T1[1] / T0);
m_r[2] = static_cast<Real>(T1[2] / T0);
/* compute inertia tensor */
m_theta(0, 0) = static_cast<Real>(density * (T2[1] + T2[2]));
m_theta(1, 1) = static_cast<Real>(density * (T2[2] + T2[0]));
m_theta(2, 2) = static_cast<Real>(density * (T2[0] + T2[1]));
m_theta(0, 1) = m_theta(1, 0) = -density * static_cast<Real>(TP[0]);
m_theta(1, 2) = m_theta(2, 1) = -density * static_cast<Real>(TP[1]);
m_theta(2, 0) = m_theta(0, 2) = -density * static_cast<Real>(TP[2]);
/* translate inertia tensor to center of mass */
m_theta(0, 0) -= m_mass * (m_r[1]*m_r[1] + m_r[2]*m_r[2]);
m_theta(1, 1) -= m_mass * (m_r[2]*m_r[2] + m_r[0]*m_r[0]);
m_theta(2, 2) -= m_mass * (m_r[0]*m_r[0] + m_r[1]*m_r[1]);
m_theta(0, 1) = m_theta(1, 0) += m_mass * m_r[0] * m_r[1];
m_theta(1, 2) = m_theta(2, 1) += m_mass * m_r[1] * m_r[2];
m_theta(2, 0) = m_theta(0, 2) += m_mass * m_r[2] * m_r[0];
m_r += m_x;
}
void VolumeIntegration::projection_integrals(unsigned int f)
{
Real a0, a1, da;
Real b0, b1, db;
Real a0_2, a0_3, a0_4, b0_2, b0_3, b0_4;
Real a1_2, a1_3, b1_2, b1_3;
Real C1, Ca, Caa, Caaa, Cb, Cbb, Cbbb;
Real Cab, Kab, Caab, Kaab, Cabb, Kabb;
P1 = Pa = Pb = Paa = Pab = Pbb = Paaa = Paab = Pabb = Pbbb = 0.0;
for (int i = 0; i < 3; i++)
{
a0 = m_vertices[m_indices[3 * f + i]][A];
b0 = m_vertices[m_indices[3 * f + i]][B];
a1 = m_vertices[m_indices[3 * f + ((i + 1) % 3)]][A];
b1 = m_vertices[m_indices[3 * f + ((i + 1) % 3)]][B];
da = a1 - a0;
db = b1 - b0;
a0_2 = a0 * a0; a0_3 = a0_2 * a0; a0_4 = a0_3 * a0;
b0_2 = b0 * b0; b0_3 = b0_2 * b0; b0_4 = b0_3 * b0;
a1_2 = a1 * a1; a1_3 = a1_2 * a1;
b1_2 = b1 * b1; b1_3 = b1_2 * b1;
C1 = a1 + a0;
Ca = a1*C1 + a0_2; Caa = a1*Ca + a0_3; Caaa = a1*Caa + a0_4;
Cb = b1*(b1 + b0) + b0_2; Cbb = b1*Cb + b0_3; Cbbb = b1*Cbb + b0_4;
Cab = 3 * a1_2 + 2 * a1*a0 + a0_2; Kab = a1_2 + 2 * a1*a0 + 3 * a0_2;
Caab = a0*Cab + 4 * a1_3; Kaab = a1*Kab + 4 * a0_3;
Cabb = 4 * b1_3 + 3 * b1_2*b0 + 2 * b1*b0_2 + b0_3;
Kabb = b1_3 + 2 * b1_2*b0 + 3 * b1*b0_2 + 4 * b0_3;
P1 += db*C1;
Pa += db*Ca;
Paa += db*Caa;
Paaa += db*Caaa;
Pb += da*Cb;
Pbb += da*Cbb;
Pbbb += da*Cbbb;
Pab += db*(b1*Cab + b0*Kab);
Paab += db*(b1*Caab + b0*Kaab);
Pabb += da*(a1*Cabb + a0*Kabb);
}
P1 /= 2.0;
Pa /= 6.0;
Paa /= 12.0;
Paaa /= 20.0;
Pb /= -6.0;
Pbb /= -12.0;
Pbbb /= -20.0;
Pab /= 24.0;
Paab /= 60.0;
Pabb /= -60.0;
}
void VolumeIntegration::face_integrals(unsigned int f)
{
Real w;
Vector3r n;
Real k1, k2, k3, k4;
projection_integrals(f);
w = m_weights[f];
n = m_face_normals[f];
k1 = (n[C] == 0) ? 0 : 1 / n[C];
k2 = k1 * k1; k3 = k2 * k1; k4 = k3 * k1;
Fa = k1 * Pa;
Fb = k1 * Pb;
Fc = -k2 * (n[A]*Pa + n[B]*Pb + w*P1);
Faa = k1 * Paa;
Fbb = k1 * Pbb;
Fcc = k3 * (SQR(n[A])*Paa + 2*n[A]*n[B]*Pab + SQR(n[B])*Pbb
+ w*(2*(n[A]*Pa + n[B]*Pb) + w*P1));
Faaa = k1 * Paaa;
Fbbb = k1 * Pbbb;
Fccc = -k4 * (CUBE(n[A])*Paaa + 3*SQR(n[A])*n[B]*Paab
+ 3*n[A]*SQR(n[B])*Pabb + CUBE(n[B])*Pbbb
+ 3*w*(SQR(n[A])*Paa + 2*n[A]*n[B]*Pab + SQR(n[B])*Pbb)
+ w*w*(3*(n[A]*Pa + n[B]*Pb) + w*P1));
Faab = k1 * Paab;
Fbbc = -k2 * (n[A]*Pabb + n[B]*Pbbb + w*Pbb);
Fcca = k3 * (SQR(n[A])*Paaa + 2*n[A]*n[B]*Paab + SQR(n[B])*Pabb
+ w*(2*(n[A]*Paa + n[B]*Pab) + w*Pa));
}
void VolumeIntegration::volume_integrals()
{
Real nx, ny, nz;
T0 = T1[0] = T1[1] = T1[2]
= T2[0] = T2[1] = T2[2]
= TP[0] = TP[1] = TP[2] = 0;
for (unsigned int i(0); i < m_nFaces; ++i)
{
Vector3r const& n = m_face_normals[i];
nx = std::abs(n[0]);
ny = std::abs(n[1]);
nz = std::abs(n[2]);
if (nx > ny && nx > nz)
C = 0;
else
C = (ny > nz) ? 1 : 2;
A = (C + 1) % 3;
B = (A + 1) % 3;
face_integrals(i);
T0 += n[0] * ((A == 0) ? Fa : ((B == 0) ? Fb : Fc));
T1[A] += n[A] * Faa;
T1[B] += n[B] * Fbb;
T1[C] += n[C] * Fcc;
T2[A] += n[A] * Faaa;
T2[B] += n[B] * Fbbb;
T2[C] += n[C] * Fccc;
TP[A] += n[A] * Faab;
TP[B] += n[B] * Fbbc;
TP[C] += n[C] * Fcca;
}
T1[0] /= 2; T1[1] /= 2; T1[2] /= 2;
T2[0] /= 3; T2[1] /= 3; T2[2] /= 3;
TP[0] /= 2; TP[1] /= 2; TP[2] /= 2;
}