Program Listing for File RigidBody.h

Return to documentation for file (Simulation/RigidBody.h)

#ifndef __RIGIDBODY_H__
#define __RIGIDBODY_H__

#include <vector>
#include "Common/Common.h"
#include "RigidBodyGeometry.h"
#include "Utils/VolumeIntegration.h"


namespace PBD
{
    class RigidBody
    {
        private:
            Real m_mass;
            Real m_invMass;
            Vector3r m_x;
            Vector3r m_lastX;
            Vector3r m_oldX;
            Vector3r m_x0;
            Vector3r m_v;
            Vector3r m_v0;
            Vector3r m_a;

            Vector3r m_inertiaTensor;
            Matrix3r m_inertiaTensorW;
            Vector3r m_inertiaTensorInverse;
            Matrix3r m_inertiaTensorInverseW;
            Quaternionr m_q;
            Quaternionr m_lastQ;
            Quaternionr m_oldQ;
            Quaternionr m_q0;
            Quaternionr m_q_mat;
            Quaternionr m_q_initial;
            Vector3r m_x0_mat;
            Matrix3r m_rot;
            Vector3r m_omega;
            Vector3r m_omega0;
            Vector3r m_torque;

            Real m_restitutionCoeff;
            Real m_frictionCoeff;

            RigidBodyGeometry m_geometry;

            // transformation required to transform a point to local space or vice vera
            Matrix3r m_transformation_R;
            Vector3r m_transformation_v1;
            Vector3r m_transformation_v2;
            Vector3r m_transformation_R_X_v1;

        public:
            RigidBody(void)
            {
            }

            ~RigidBody(void)
            {
            }

            void initBody(const Real mass, const Vector3r &x,
                const Vector3r &inertiaTensor, const Quaternionr &rotation,
                const VertexData &vertices, const Utilities::IndexedFaceMesh &mesh,
                const Vector3r &scale = Vector3r(1.0, 1.0, 1.0))
            {
                setMass(mass);
                m_x = x;
                m_x0 = x;
                m_lastX = x;
                m_oldX = x;
                m_v.setZero();
                m_v0.setZero();
                m_a.setZero();

                setInertiaTensor(inertiaTensor);
                m_q = rotation;
                m_q0 = rotation;
                m_lastQ = rotation;
                m_oldQ = rotation;
                m_rot = m_q.matrix();
                m_q_mat = Quaternionr(1.0, 0.0, 0.0, 0.0);
                m_q_initial = Quaternionr(1.0, 0.0, 0.0, 0.0);
                m_x0_mat.setZero();
                rotationUpdated();
                m_omega.setZero();
                m_omega0.setZero();
                m_torque.setZero();

                m_restitutionCoeff = static_cast<Real>(0.6);
                m_frictionCoeff = static_cast<Real>(0.2);

                getGeometry().initMesh(vertices.size(), mesh.numFaces(), &vertices.getPosition(0), mesh.getFaces().data(), mesh.getUVIndices(), mesh.getUVs(), scale, mesh.getFlatShading());
                getGeometry().updateMeshTransformation(getPosition(), getRotationMatrix());
            }

            void initBody(const Real density, const Vector3r &x, const Quaternionr &rotation,
                const VertexData &vertices, const Utilities::IndexedFaceMesh &mesh, const Vector3r &scale = Vector3r(1.0, 1.0, 1.0))
            {
                m_mass = 1.0;
                m_inertiaTensor = Vector3r(1.0, 1.0, 1.0);
                m_x = x;
                m_x0 = x;
                m_lastX = x;
                m_oldX = x;
                m_v.setZero();
                m_v0.setZero();
                m_a.setZero();

                m_q = rotation;
                m_q0 = rotation;
                m_lastQ = rotation;
                m_oldQ = rotation;
                m_rot = m_q.matrix();
                rotationUpdated();
                m_omega.setZero();
                m_omega0.setZero();
                m_torque.setZero();

                m_restitutionCoeff = static_cast<Real>(0.6);
                m_frictionCoeff = static_cast<Real>(0.2);

                getGeometry().initMesh(vertices.size(), mesh.numFaces(), &vertices.getPosition(0), mesh.getFaces().data(), mesh.getUVIndices(), mesh.getUVs(), scale, mesh.getFlatShading());
                determineMassProperties(density);
                getGeometry().updateMeshTransformation(getPosition(), getRotationMatrix());
            }

            void reset()
            {
                getPosition() = getPosition0();
                getOldPosition() = getPosition0();
                getLastPosition() = getPosition0();

                getRotation() = getRotation0();
                getOldRotation() = getRotation0();
                getLastRotation() = getRotation0();

                getVelocity() = getVelocity0();
                getAngularVelocity() = getAngularVelocity0();

                getAcceleration().setZero();
                getTorque().setZero();

                rotationUpdated();
            }

            void updateInverseTransformation()
            {
                // remove the rotation of the main axis transformation that is performed
                // to get a diagonal inertia tensor since the distance function is
                // evaluated in local coordinates
                //
                // transformation world to local:
                // p_local = R_initial^T ( R_MAT R^T (p_world - x) - x_initial + x_MAT)
                //
                // transformation local to world:
                // p_world = R R_MAT^T (R_initial p_local + x_initial - x_MAT) + x
                //
                m_transformation_R = (getRotationInitial().inverse() * getRotationMAT() * getRotation().inverse()).matrix();
                m_transformation_v1 = -getRotationInitial().inverse().matrix() * getPositionInitial_MAT();
                m_transformation_v2 = (getRotation()*getRotationMAT().inverse()).matrix() * getPositionInitial_MAT() + getPosition();
                m_transformation_R_X_v1 = -m_transformation_R * getPosition() + m_transformation_v1;
            }

            void rotationUpdated()
            {
                if (m_mass != 0.0)
                {
                    m_rot = m_q.matrix();
                    updateInertiaW();
                    updateInverseTransformation();
                }
            }

            void updateInertiaW()
            {
                if (m_mass != 0.0)
                {
                    m_inertiaTensorW = m_rot * m_inertiaTensor.asDiagonal() * m_rot.transpose();
                    m_inertiaTensorInverseW = m_rot * m_inertiaTensorInverse.asDiagonal() * m_rot.transpose();
                }
            }

            void determineMassProperties(const Real density)
            {
                // apply initial rotation
                VertexData &vd = m_geometry.getVertexDataLocal();

                Utilities::VolumeIntegration vi(m_geometry.getVertexDataLocal().size(), m_geometry.getMesh().numFaces(), &m_geometry.getVertexDataLocal().getPosition(0), m_geometry.getMesh().getFaces().data());
                vi.compute_inertia_tensor(density);

                // Diagonalize Inertia Tensor
                Eigen::SelfAdjointEigenSolver<Matrix3r> es(vi.getInertia());
                Vector3r inertiaTensor = es.eigenvalues();
                Matrix3r R = es.eigenvectors();

                setMass(vi.getMass());
                setInertiaTensor(inertiaTensor);

                if (R.determinant() < 0.0)
                    R = -R;

                for (unsigned int i = 0; i < vd.size(); i++)
                    vd.getPosition(i) = m_rot * vd.getPosition(i) + m_x0;

                Vector3r x_MAT = vi.getCenterOfMass();
                R = m_rot * R;
                x_MAT = m_rot * x_MAT + m_x0;

                // rotate vertices back
                for (unsigned int i = 0; i < vd.size(); i++)
                    vd.getPosition(i) = R.transpose() * (vd.getPosition(i) - x_MAT);

                // set rotation
                Quaternionr qR = Quaternionr(R);
                qR.normalize();
                m_q_mat = qR;
                m_q_initial = m_q0;
                m_x0_mat = m_x0 - x_MAT;

                m_q0 = qR;
                m_q = m_q0;
                m_lastQ = m_q0;
                m_oldQ = m_q0;
                rotationUpdated();

                // set translation
                m_x0 = x_MAT;
                m_x = m_x0;
                m_lastX = m_x0;
                m_oldX = m_x0;
                updateInverseTransformation();
            }

            const Matrix3r &getTransformationR() { return m_transformation_R;  }
            const Vector3r &getTransformationV1() { return m_transformation_v1; }
            const Vector3r &getTransformationV2() { return m_transformation_v2; }
            const Vector3r &getTransformationRXV1() { return m_transformation_R_X_v1; }

            FORCE_INLINE Real &getMass()
            {
                return m_mass;
            }

            FORCE_INLINE const Real &getMass() const
            {
                return m_mass;
            }

            FORCE_INLINE void setMass(const Real &value)
            {
                m_mass = value;
                if (m_mass != 0.0)
                    m_invMass = static_cast<Real>(1.0) / m_mass;
                else
                    m_invMass = 0.0;
            }

            FORCE_INLINE const Real &getInvMass() const
            {
                return m_invMass;
            }

            FORCE_INLINE Vector3r &getPosition()
            {
                return m_x;
            }

            FORCE_INLINE const Vector3r &getPosition() const
            {
                return m_x;
            }

            FORCE_INLINE void setPosition(const Vector3r &pos)
            {
                m_x = pos;
            }

            FORCE_INLINE Vector3r &getLastPosition()
            {
                return m_lastX;
            }

            FORCE_INLINE const Vector3r &getLastPosition() const
            {
                return m_lastX;
            }

            FORCE_INLINE void setLastPosition(const Vector3r &pos)
            {
                m_lastX = pos;
            }

            FORCE_INLINE Vector3r &getOldPosition()
            {
                return m_oldX;
            }

            FORCE_INLINE const Vector3r &getOldPosition() const
            {
                return m_oldX;
            }

            FORCE_INLINE void setOldPosition(const Vector3r &pos)
            {
                m_oldX = pos;
            }

            FORCE_INLINE Vector3r &getPosition0()
            {
                return m_x0;
            }

            FORCE_INLINE const Vector3r &getPosition0() const
            {
                return m_x0;
            }

            FORCE_INLINE void setPosition0(const Vector3r &pos)
            {
                m_x0 = pos;
            }

            FORCE_INLINE Vector3r &getPositionInitial_MAT()
            {
                return m_x0_mat;
            }

            FORCE_INLINE const Vector3r &getPositionInitial_MAT() const
            {
                return m_x0_mat;
            }

            FORCE_INLINE void setPositionInitial_MAT(const Vector3r &pos)
            {
                m_x0_mat = pos;
            }

            FORCE_INLINE Vector3r &getVelocity()
            {
                return m_v;
            }

            FORCE_INLINE const Vector3r &getVelocity() const
            {
                return m_v;
            }

            FORCE_INLINE void setVelocity(const Vector3r &value)
            {
                m_v = value;
            }

            FORCE_INLINE Vector3r &getVelocity0()
            {
                return m_v0;
            }

            FORCE_INLINE const Vector3r &getVelocity0() const
            {
                return m_v0;
            }

            FORCE_INLINE void setVelocity0(const Vector3r &value)
            {
                m_v0 = value;
            }

            FORCE_INLINE Vector3r &getAcceleration()
            {
                return m_a;
            }

            FORCE_INLINE const Vector3r &getAcceleration() const
            {
                return m_a;
            }

            FORCE_INLINE void setAcceleration(const Vector3r &accel)
            {
                m_a = accel;
            }

            FORCE_INLINE const Vector3r &getInertiaTensor() const
            {
                return m_inertiaTensor;
            }

            FORCE_INLINE void setInertiaTensor(const Vector3r &value)
            {
                m_inertiaTensor = value;
                m_inertiaTensorInverse = Vector3r(static_cast<Real>(1.0) / value[0], static_cast<Real>(1.0) / value[1], static_cast<Real>(1.0) / value[2]);
            }

            FORCE_INLINE Matrix3r& getInertiaTensorW()
            {
                return m_inertiaTensorW;
            }

            FORCE_INLINE const Matrix3r& getInertiaTensorW() const
            {
                return m_inertiaTensorW;
            }

            FORCE_INLINE const Vector3r &getInertiaTensorInverse() const
            {
                return m_inertiaTensorInverse;
            }

            FORCE_INLINE Matrix3r &getInertiaTensorInverseW()
            {
                return m_inertiaTensorInverseW;
            }

            FORCE_INLINE const Matrix3r &getInertiaTensorInverseW() const
            {
                return m_inertiaTensorInverseW;
            }

            FORCE_INLINE void setInertiaTensorInverseW(const Matrix3r &value)
            {
                m_inertiaTensorInverseW = value;
            }

            FORCE_INLINE Quaternionr &getRotation()
            {
                return m_q;
            }

            FORCE_INLINE const Quaternionr &getRotation() const
            {
                return m_q;
            }

            FORCE_INLINE void setRotation(const Quaternionr &value)
            {
                m_q = value;
            }

            FORCE_INLINE Quaternionr &getLastRotation()
            {
                return m_lastQ;
            }

            FORCE_INLINE const Quaternionr &getLastRotation() const
            {
                return m_lastQ;
            }

            FORCE_INLINE void setLastRotation(const Quaternionr &value)
            {
                m_lastQ = value;
            }

            FORCE_INLINE Quaternionr &getOldRotation()
            {
                return m_oldQ;
            }

            FORCE_INLINE const Quaternionr &getOldRotation() const
            {
                return m_oldQ;
            }

            FORCE_INLINE void setOldRotation(const Quaternionr &value)
            {
                m_oldQ = value;
            }

            FORCE_INLINE Quaternionr &getRotation0()
            {
                return m_q0;
            }

            FORCE_INLINE const Quaternionr &getRotation0() const
            {
                return m_q0;
            }

            FORCE_INLINE void setRotation0(const Quaternionr &value)
            {
                m_q0 = value;
            }

            FORCE_INLINE Quaternionr &getRotationMAT()
            {
                return m_q_mat;
            }

            FORCE_INLINE const Quaternionr &getRotationMAT() const
            {
                return m_q_mat;
            }

            FORCE_INLINE void setRotationMAT(const Quaternionr &value)
            {
                m_q_mat = value;
            }

            FORCE_INLINE Quaternionr &getRotationInitial()
            {
                return m_q_initial;
            }

            FORCE_INLINE const Quaternionr &getRotationInitial() const
            {
                return m_q_initial;
            }

            FORCE_INLINE void setRotationInitial(const Quaternionr &value)
            {
                m_q_initial = value;
            }

            FORCE_INLINE Matrix3r &getRotationMatrix()
            {
                return m_rot;
            }

            FORCE_INLINE const Matrix3r &getRotationMatrix() const
            {
                return m_rot;
            }

            FORCE_INLINE void setRotationMatrix(const Matrix3r &value)
            {
                m_rot = value;
            }

            FORCE_INLINE Vector3r &getAngularVelocity()
            {
                return m_omega;
            }

            FORCE_INLINE const Vector3r &getAngularVelocity() const
            {
                return m_omega;
            }

            FORCE_INLINE void setAngularVelocity(const Vector3r &value)
            {
                m_omega = value;
            }

            FORCE_INLINE Vector3r &getAngularVelocity0()
            {
                return m_omega0;
            }

            FORCE_INLINE const Vector3r &getAngularVelocity0() const
            {
                return m_omega0;
            }

            FORCE_INLINE void setAngularVelocity0(const Vector3r &value)
            {
                m_omega0 = value;
            }

            FORCE_INLINE Vector3r &getTorque()
            {
                return m_torque;
            }

            FORCE_INLINE const Vector3r &getTorque() const
            {
                return m_torque;
            }

            FORCE_INLINE void setTorque(const Vector3r &value)
            {
                m_torque = value;
            }

            FORCE_INLINE Real getRestitutionCoeff() const
            {
                return m_restitutionCoeff;
            }

            FORCE_INLINE void setRestitutionCoeff(Real val)
            {
                m_restitutionCoeff = val;
            }

            FORCE_INLINE Real getFrictionCoeff() const
            {
                return m_frictionCoeff;
            }

            FORCE_INLINE void setFrictionCoeff(Real val)
            {
                m_frictionCoeff = val;
            }

            RigidBodyGeometry& getGeometry()
            {
                return m_geometry;
            }
    };
}

#endif