diff --git a/Base/Constraint/imstkPbdAreaConstraint.cpp b/Base/Constraint/imstkPbdAreaConstraint.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f1726b24d6eb82999b3d4b65cdfb820f3b78ca2b --- /dev/null +++ b/Base/Constraint/imstkPbdAreaConstraint.cpp @@ -0,0 +1,106 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + =========================================================================*/ + +#include "imstkPbdAreaConstraint.h" +#include "imstkPbdModel.h" + +namespace imstk +{ + +void +AreaConstraint::initConstraint(PositionBasedModel &model, const unsigned int &pIdx1, + const unsigned int &pIdx2, const unsigned int &pIdx3, + const double k) +{ + m_bodies[0] = pIdx1; + m_bodies[1] = pIdx2; + m_bodies[2] = pIdx3; + + m_stiffness = k; + + auto state = model.getState(); + + const Vec3d &p0 = state->getInitialVertexPosition(pIdx1); + const Vec3d &p1 = state->getInitialVertexPosition(pIdx2); + const Vec3d &p2 = state->getInitialVertexPosition(pIdx3); + + m_restArea = 0.5*(p1 - p0).cross(p2 - p0).norm(); +} + +bool +AreaConstraint::solvePositionConstraint(PositionBasedModel &model) +{ + const unsigned int i1 = m_bodies[0]; + const unsigned int i2 = m_bodies[1]; + const unsigned int i3 = m_bodies[2]; + + auto state = model.getState(); + + Vec3d &p0 = state->getVertexPosition(i1); + Vec3d &p1 = state->getVertexPosition(i2); + Vec3d &p2 = state->getVertexPosition(i3); + + const double im0 = state->getInvMass(i1); + const double im1 = state->getInvMass(i2); + const double im2 = state->getInvMass(i3); + + const Vec3d e1 = p0 - p1; + const Vec3d e2 = p1 - p2; + const Vec3d e3 = p2 - p0; + + Vec3d n = e1.cross(e2); + const double A = 0.5*n.norm(); + + if (A < EPS) + { + return false; + } + + n /= 2 * A; + + const Vec3d grad0 = e2.cross(n); + const Vec3d grad1 = e3.cross(n); + const Vec3d grad2 = e1.cross(n); + + double lambda = im0*grad0.squaredNorm() + im1*grad1.squaredNorm() + im2*grad2.squaredNorm(); + + lambda = (A - m_restArea) / lambda * m_stiffness; + + if (im0 > 0) + { + p0 += -im0*lambda*grad0; + } + + if (im1 > 0) + { + p1 += -im1*lambda*grad1; + } + + if (im2 > 0) + { + p2 += -im2*lambda*grad2; + } + + return true; +} + + +} // imstk \ No newline at end of file diff --git a/Base/Constraint/imstkPbdAreaConstraint.h b/Base/Constraint/imstkPbdAreaConstraint.h new file mode 100644 index 0000000000000000000000000000000000000000..a6538c442d7a3e653eb886d0047727d740331bc2 --- /dev/null +++ b/Base/Constraint/imstkPbdAreaConstraint.h @@ -0,0 +1,68 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + =========================================================================*/ + +#ifndef IMSTK_PBD_AREA_CONSTRAINT_H +#define IMSTK_PBD_AREA_CONSTRAINT_H + +#include "imstkPbdConstraint.h" + +namespace imstk +{ + +//// +/// \class AreaConstraint +/// +/// \brief Area constraint for triangular face +/// +class AreaConstraint : public PbdConstraint +{ +public: + /// + /// \brief Constructor + /// + AreaConstraint() : PbdConstraint(3) {} + + /// + /// \brief Returns PBD constraint of type Type::Area + /// + Type getType() const + { + return Type::Area; + } + + /// + /// \brief Initializes the area constraint + /// + void initConstraint(PositionBasedModel& model, const unsigned int& pIdx1, + const unsigned int& pIdx2, const unsigned int& pIdx3, const double k = 2.5); + + /// + /// \brief Solves the area constraint + /// + bool solvePositionConstraint(PositionBasedModel &model); + +public: + double m_restArea; ///> Area at the rest position + double m_stiffness; ///> Stiffness of the area constraint +}; +} + +#endif // IMSTK_PBD_AREA_CONSTRAINT_H \ No newline at end of file diff --git a/Base/Constraint/imstkPbdConstraint.cpp b/Base/Constraint/imstkPbdConstraint.cpp deleted file mode 100644 index 320d6d46d95b7bf1424c0e0ce06fa4241e008d00..0000000000000000000000000000000000000000 --- a/Base/Constraint/imstkPbdConstraint.cpp +++ /dev/null @@ -1,484 +0,0 @@ -/*========================================================================= - - Library: iMSTK - - Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, - & Imaging in Medicine, Rensselaer Polytechnic Institute. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0.txt - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - =========================================================================*/ - -#include "imstkPbdConstraint.h" -#include "imstkPbdModel.h" - -namespace imstk -{ - -using Vec3d = Eigen::Vector3d; -using Mat3d = Eigen::Matrix3d; - -bool -FEMTetConstraint::initConstraint (PositionBasedModel &model, - const unsigned int &pIdx1, const unsigned int &pIdx2, - const unsigned int &pIdx3, const unsigned int &pIdx4) -{ - m_bodies[0] = pIdx1; - m_bodies[1] = pIdx2; - m_bodies[2] = pIdx3; - m_bodies[3] = pIdx4; - - auto state = model.getState(); - - Vec3d &p0 = state->getInitialVertexPosition(pIdx1); - Vec3d &p1 = state->getInitialVertexPosition(pIdx2); - Vec3d &p2 = state->getInitialVertexPosition(pIdx3); - Vec3d &p3 = state->getInitialVertexPosition(pIdx4); - - m_Volume = (1.0 / 6.0) * (p3 - p0).dot((p1 - p0).cross(p2 - p0)); - - Mat3d m; - m.col(0) = p0 - p3; - m.col(1) = p1 - p3; - m.col(2) = p2 - p3; - - double det = m.determinant(); - if (fabs(det) > EPS) - { - m_invRestMat = m.inverse(); - return true; - } - - return false; -} - -bool -FEMTetConstraint::solvePositionConstraint(PositionBasedModel &model) -{ - const unsigned int i1 = m_bodies[0]; - const unsigned int i2 = m_bodies[1]; - const unsigned int i3 = m_bodies[2]; - const unsigned int i4 = m_bodies[3]; - - auto state = model.getState(); - - Vec3d &p0 = state->getVertexPosition(i1); - Vec3d &p1 = state->getVertexPosition(i2); - Vec3d &p2 = state->getVertexPosition(i3); - Vec3d &p3 = state->getVertexPosition(i4); - - double currentVolume = (1.0 / 6.0) * (p3 - p0).dot((p1 - p0).cross(p2 - p0)); - - Mat3d m; - m.col(0) = p0 - p3; - m.col(1) = p1 - p3; - m.col(2) = p2 - p3; - - // deformation gradient - Mat3d F = m*m_invRestMat; - // First Piola-Kirchhoff tensor - Mat3d P; - // energy constraint - double C = 0; - - double mu = model.getFirstLame(); - double lambda = model.getSecondLame(); - - switch (m_material) - { - - // P(F) = F*(2*mu*E + lambda*tr(E)*I) - // E = (F^T*F - I)/2 - case MaterialType::StVK : - { - Mat3d E; - E(0, 0) = 0.5*(F(0, 0) * F(0, 0) + F(1, 0) * F(1, 0) + F(2, 0) * F(2, 0) - 1.0); // xx - E(1, 1) = 0.5*(F(0, 1) * F(0, 1) + F(1, 1) * F(1, 1) + F(2, 1) * F(2, 1) - 1.0); // yy - E(2, 2) = 0.5*(F(0, 2) * F(0, 2) + F(1, 2) * F(1, 2) + F(2, 2) * F(2, 2) - 1.0); // zz - E(0, 1) = 0.5*(F(0, 0) * F(0, 1) + F(1, 0) * F(1, 1) + F(2, 0) * F(2, 1)); // xy - E(0, 2) = 0.5*(F(0, 0) * F(0, 2) + F(1, 0) * F(1, 2) + F(2, 0) * F(2, 2)); // xz - E(1, 2) = 0.5*(F(0, 1) * F(0, 2) + F(1, 1) * F(1, 2) + F(2, 1) * F(2, 2)); // yz - E(1, 0) = E(0, 1); - E(2, 0) = E(0, 2); - E(2, 1) = E(1, 2); - - P = 2*mu*E; - double tr = E.trace(); - double lt = lambda*tr; - P(0,0) += lt; - P(1,1) += lt; - P(2,2) += lt; - P = F*P; - - C = E(0,0)*E(0,0) + E(0,1)*E(0,1) + E(0,2)*E(0,2) - + E(1,0)*E(1,0) + E(1,1)*E(1,1) + E(1,2)*E(1,2) - + E(2,0)*E(2,0) + E(2,1)*E(2,1) + E(2,2)*E(2,2); - C = mu*C + 0.5*lambda*tr*tr; - - break; - } - - // P(F) = (2*mu*(F-R) + lambda*(J-1)*J*F^-T - case MaterialType::Corotation : - { - Eigen::JacobiSVD<Mat3d> svd(F, Eigen::ComputeFullU | Eigen::ComputeFullV); - Mat3d R = svd.matrixU()*svd.matrixV().adjoint(); - Vec3d Sigma(svd.singularValues()); - Mat3d invFT = svd.matrixU(); - invFT.col(0) /= Sigma(0); - invFT.col(1) /= Sigma(1); - invFT.col(2) /= Sigma(2); - invFT *= svd.matrixV().adjoint(); - double J = Sigma(0)*Sigma(1)*Sigma(2); - Mat3d FR = F - R; - - P = 2*mu*FR + lambda*(J-1)*J*invFT; - - C = FR(0,0)*FR(0,0) + FR(0,1)*FR(0,1) + FR(0,2)*FR(0,2) - + FR(1,0)*FR(1,0) + FR(1,1)*FR(1,1) + FR(1,2)*FR(1,2) - + FR(2,0)*FR(2,0) + FR(2,1)*FR(2,1) + FR(2,2)*FR(2,2); - C = mu*C + 0.5*lambda*(J-1)*(J-1); - - break; - } - // P(F) = mu*(F - mu*F^-T) + lambda*log(J)F^-T; - case MaterialType::NeoHookean : - { - Mat3d invFT = F.inverse().transpose(); - double logJ = log(F.determinant()); - P = mu*(F - invFT) + lambda*logJ*invFT; - - C = F(0,0)*F(0,0) + F(0,1)*F(0,1) + F(0,2)*F(0,2) - + F(1,0)*F(1,0) + F(1,1)*F(1,1) + F(1,2)*F(1,2) - + F(2,0)*F(2,0) + F(2,1)*F(2,1) + F(2,2)*F(2,2); - - C = 0.5*mu*(C-3) - mu*logJ + 0.5*lambda*logJ*logJ; - - break; - } - - case MaterialType::Linear : - { - break; - } - - default: { - printf("Material type not supported ! \n") ; - break; - } - } - - const double im1 = state->getInvMass(i1); - const double im2 = state->getInvMass(i2); - const double im3 = state->getInvMass(i3); - const double im4 = state->getInvMass(i4); - - Mat3d gradC = m_Volume*P*m_invRestMat.transpose(); - - double sum = im1*gradC.col(0).squaredNorm() - + im2*gradC.col(1).squaredNorm() - + im3*gradC.col(2).squaredNorm() - + im4*(gradC.col(0) + gradC.col(1) + gradC.col(2)).squaredNorm(); - - if (sum < EPS) - return false; - - C = C*m_Volume; - - double s = C/sum; - - if (im1 > 0) - p0 += -s*im1*gradC.col(0); - if (im2 > 0) - p1 += -s*im2*gradC.col(1); - if (im3 > 0) - p2 += -s*im3*gradC.col(2); - if (im4 > 0) - p3 += s*im4*(gradC.col(0) + gradC.col(1) + gradC.col(2)); - - return true; -} - -void -DistanceConstraint::initConstraint(PositionBasedModel &model, const unsigned int &pIdx1, - const unsigned int &pIdx2, const double k) -{ - m_bodies[0] = pIdx1; - m_bodies[1] = pIdx2; - m_stiffness = k; - auto state = model.getState(); - Vec3d &p1 = state->getInitialVertexPosition(pIdx1); - Vec3d &p2 = state->getInitialVertexPosition(pIdx2); - m_restLength = (p1 - p2).norm(); -} - -bool -DistanceConstraint::solvePositionConstraint(PositionBasedModel &model) -{ - const unsigned int i1 = m_bodies[0]; - const unsigned int i2 = m_bodies[1]; - - auto state = model.getState(); - - Vec3d &p0 = state->getVertexPosition(i1); - Vec3d &p1 = state->getVertexPosition(i2); - - const double im1 = state->getInvMass(i1); - const double im2 = state->getInvMass(i2); - - double wsum = im1 + im2; - - if (wsum == 0.0) - return false; - Vec3d n = p1 - p0; - double len = n.norm(); - n /= len; - - Vec3d gradC = m_stiffness*n*(len - m_restLength)/wsum; - - if (im1 > 0) - p0 += im1*gradC; - if (im2 > 0) - p1 += -im2*gradC; - - return true; -} - -void -DihedralConstraint::initConstraint(PositionBasedModel &model, - const unsigned int &pIdx1, const unsigned int &pIdx2, - const unsigned int &pIdx3, const unsigned int &pIdx4, - const double k) -{ - m_bodies[0] = pIdx1; - m_bodies[1] = pIdx2; - m_bodies[2] = pIdx3; - m_bodies[3] = pIdx4; - - m_stiffness = k; - auto state = model.getState(); - - Vec3d &p0 = state->getInitialVertexPosition(pIdx1); - Vec3d &p1 = state->getInitialVertexPosition(pIdx2); - Vec3d &p2 = state->getInitialVertexPosition(pIdx3); - Vec3d &p3 = state->getInitialVertexPosition(pIdx4); - - Vec3d n1 = (p2 - p0).cross(p3 - p0).normalized(); - Vec3d n2 = (p3 - p1).cross(p2 - p1).normalized(); - - m_restAngle = atan2(n1.cross(n2).dot(p3-p2), (p3-p2).norm()*n1.dot(n2)); -} - -bool -DihedralConstraint::solvePositionConstraint(PositionBasedModel &model) -{ - const unsigned int i1 = m_bodies[0]; - const unsigned int i2 = m_bodies[1]; - const unsigned int i3 = m_bodies[2]; - const unsigned int i4 = m_bodies[3]; - - auto state = model.getState(); - - Vec3d &p0 = state->getVertexPosition(i1); - Vec3d &p1 = state->getVertexPosition(i2); - Vec3d &p2 = state->getVertexPosition(i3); - Vec3d &p3 = state->getVertexPosition(i4); - - const double im0 = state->getInvMass(i1); - const double im1 = state->getInvMass(i2); - const double im2 = state->getInvMass(i3); - const double im3 = state->getInvMass(i4); - - if (im0 == 0.0 && im1 == 0.0) - return false; - Vec3d e = p3 - p2; - Vec3d e1 = p3 - p0; - Vec3d e2 = p0 - p2; - Vec3d e3 = p3 - p1; - Vec3d e4 = p1 - p2; - // To accelerate, all normal (area) vectors and edge length should be precomputed in parallel - Vec3d n1 = e1.cross(e); - Vec3d n2 = e.cross(e3); - double A1 = n1.norm(); - double A2 = n2.norm(); - n1 /= A1; - n2 /= A2; - - double l = e.norm(); - if ( l < EPS ) - return false; - - Vec3d grad0 = -(l/A1)*n1; - Vec3d grad1 = -(l/A2)*n2; - Vec3d grad2 = (e.dot(e1)/(A1*l))*n1 + (e.dot(e3)/(A2*l))*n2 ; - Vec3d grad3 = (e.dot(e2)/(A1*l))*n1 + (e.dot(e4)/(A2*l))*n2 ; - - double lambda = im0*grad0.squaredNorm() + - im1*grad1.squaredNorm() + - im2*grad2.squaredNorm() + - im3*grad3.squaredNorm(); - - // huge difference if use acos instead of atan2 - lambda = (atan2(n1.cross(n2).dot(e), l*n1.dot(n2)) - m_restAngle) / lambda * m_stiffness; - - if (im0 > 0) - p0 += -im0*lambda*grad0; - if (im1 > 0) - p1 += -im1*lambda*grad1; - if (im2 > 0) - p2 += -im2*lambda*grad2; - if (im3 > 0) - p3 += -im3*lambda*grad3; - - return true; -} - -void -AreaConstraint::initConstraint(PositionBasedModel &model, const unsigned int &pIdx1, - const unsigned int &pIdx2, const unsigned int &pIdx3, - const double k) -{ - m_bodies[0] = pIdx1; - m_bodies[1] = pIdx2; - m_bodies[2] = pIdx3; - - m_stiffness = k; - - auto state = model.getState(); - - Vec3d &p0 = state->getInitialVertexPosition(pIdx1); - Vec3d &p1 = state->getInitialVertexPosition(pIdx2); - Vec3d &p2 = state->getInitialVertexPosition(pIdx3); - - m_restArea = 0.5*(p1 - p0).cross(p2 - p0).norm(); -} - -bool -AreaConstraint::solvePositionConstraint(PositionBasedModel &model) -{ - const unsigned int i1 = m_bodies[0]; - const unsigned int i2 = m_bodies[1]; - const unsigned int i3 = m_bodies[2]; - - auto state = model.getState(); - - Vec3d &p0 = state->getVertexPosition(i1); - Vec3d &p1 = state->getVertexPosition(i2); - Vec3d &p2 = state->getVertexPosition(i3); - - const double im0 = state->getInvMass(i1); - const double im1 = state->getInvMass(i2); - const double im2 = state->getInvMass(i3); - - Vec3d e1 = p0 - p1; - Vec3d e2 = p1 - p2; - Vec3d e3 = p2 - p0; - - Vec3d n = e1.cross(e2); - double A = 0.5*n.norm(); - - if (A < EPS) - return false; - - n /= 2*A; - - Vec3d grad0 = e2.cross(n); - Vec3d grad1 = e3.cross(n); - Vec3d grad2 = e1.cross(n); - - double lambda = im0*grad0.squaredNorm() + im1*grad1.squaredNorm() + im2*grad2.squaredNorm(); - - lambda = (A - m_restArea) / lambda * m_stiffness; - - - if (im0 > 0) - p0 += -im0*lambda*grad0; - if (im1 > 0) - p1 += -im1*lambda*grad1; - if (im2 > 0) - p2 += -im2*lambda*grad2; - - return true; -} - -void -VolumeConstraint::initConstraint(PositionBasedModel &model, const unsigned int &pIdx1, - const unsigned int &pIdx2, const unsigned int &pIdx3, - const unsigned int &pIdx4, const double k) -{ - m_bodies[0] = pIdx1; - m_bodies[1] = pIdx2; - m_bodies[2] = pIdx3; - m_bodies[3] = pIdx4; - - m_stiffness = k; - - auto state = model.getState(); - - Vec3d &p0 = state->getInitialVertexPosition(pIdx1); - Vec3d &p1 = state->getInitialVertexPosition(pIdx2); - Vec3d &p2 = state->getInitialVertexPosition(pIdx3); - Vec3d &p3 = state->getInitialVertexPosition(pIdx4); - - m_restVolume = (1.0/6.0)*((p1-p0).cross(p2-p0)).dot(p3-p0); -} - -bool -VolumeConstraint::solvePositionConstraint(PositionBasedModel &model) -{ - const unsigned int i1 = m_bodies[0]; - const unsigned int i2 = m_bodies[1]; - const unsigned int i3 = m_bodies[2]; - const unsigned int i4 = m_bodies[3]; - - auto state = model.getState(); - - Vec3d &x1 = state->getVertexPosition(i1); - Vec3d &x2 = state->getVertexPosition(i2); - Vec3d &x3 = state->getVertexPosition(i3); - Vec3d &x4 = state->getVertexPosition(i4); - - const double im1 = state->getInvMass(i1); - const double im2 = state->getInvMass(i2); - const double im3 = state->getInvMass(i3); - const double im4 = state->getInvMass(i4); - - double onesixth = 1.0/6.0; - - Vec3d grad1 = onesixth*(x2-x3).cross(x4-x2); - Vec3d grad2 = onesixth*(x3-x1).cross(x4-x1); - Vec3d grad3 = onesixth*(x4-x1).cross(x2-x1); - Vec3d grad4 = onesixth*(x2-x1).cross(x3-x1); - - double V = grad4.dot(x4-x1); - - double lambda = im1*grad1.squaredNorm() + - im2*grad2.squaredNorm() + - im3*grad3.squaredNorm() + - im4*grad4.squaredNorm(); - - lambda = (V - m_restVolume)/lambda * m_stiffness; - - if (im1 > 0) - x1 += -im1*lambda*grad1; - if (im1 > 0) - x2 += -im2*lambda*grad2; - if (im3 > 0) - x3 += -im3*lambda*grad3; - if (im4 > 0) - x4 += -im4*lambda*grad4; - - return true; -} - -} // imstk diff --git a/Base/Constraint/imstkPbdConstraint.h b/Base/Constraint/imstkPbdConstraint.h index 33fd2782e949cf61e6d230a24da369ccca312394..37b6db778e67178ccd5ba50a2e284a96145eeb76 100644 --- a/Base/Constraint/imstkPbdConstraint.h +++ b/Base/Constraint/imstkPbdConstraint.h @@ -19,8 +19,8 @@ =========================================================================*/ -#ifndef IMSTKPBDCONSTRAINT_H -#define IMSTKPBDCONSTRAINT_H +#ifndef IMSTK_PBD_CONSTRAINT_H +#define IMSTK_PBD_CONSTRAINT_H #include "imstkMath.h" @@ -32,11 +32,14 @@ namespace imstk class PositionBasedModel; /// -/// \brief Based Constraint class for Position based dynamics +/// \brief Base Constraint class for Position based dynamics constraints /// class PbdConstraint { public: + /// + /// \brief Type of the PBD constraint + /// enum class Type { Distance, @@ -95,268 +98,6 @@ public: std::vector<unsigned int> m_bodies; // index of points for the constraint }; -/// -/// \class DistanceConstraint -/// -/// \brief -/// -class DistanceConstraint : public PbdConstraint -{ -public: - /// - /// \brief - /// - DistanceConstraint() : PbdConstraint(2) {} - - /// - /// \brief - /// - Type getType() const { return Type::Distance; } - - /// - /// \brief - /// - void initConstraint(PositionBasedModel& model, const unsigned int& pIdx1, - const unsigned int& pIdx2, const double k = 1e-1); - - /// - /// \brief - /// - bool solvePositionConstraint(PositionBasedModel &model); - -public: - double m_restLength; - double m_stiffness; -}; - -/// -/// \class DihedralConstraint -/// -/// \brief -/// -class DihedralConstraint : public PbdConstraint -{ -public: - /// - /// \brief - /// - DihedralConstraint() : PbdConstraint(4) {} - /// - /// \brief - /// - Type getType() const { return Type::Dihedral; } - - /// - /// \brief initConstraint - /// p3 - /// / | \ - /// / | \ - /// p0 | p1 - /// \ | / - /// \ | / - /// p2 - /// \param model - /// \param pIdx1 index of p0 - /// \param pIdx2 index of p1 - /// \param pIdx3 index of p2 - /// \param pIdx4 index of p3 - /// \param k stiffness - /// - void initConstraint(PositionBasedModel& model, const unsigned int& pIdx1, const unsigned int& pIdx2, - const unsigned int& pIdx3, const unsigned int& pIdx4, const double k = 1e-3 ); - - /// - /// \brief - /// - bool solvePositionConstraint(PositionBasedModel &model); - -public: - double m_restAngle; - double m_stiffness; -}; - -/// -/// \class AreaConstraint -/// -/// \brief -/// -class AreaConstraint : public PbdConstraint -{ -public: - /// - /// \brief - /// - AreaConstraint() : PbdConstraint(3) - {} - - /// - /// \brief - /// - Type getType() const - { - return Type::Area; - } - - /// - /// \brief - /// - void initConstraint(PositionBasedModel& model, const unsigned int& pIdx1, - const unsigned int& pIdx2, const unsigned int& pIdx3, const double k = 2.5); - - /// - /// \brief - /// - bool solvePositionConstraint(PositionBasedModel &model); - -public: - double m_restArea; - double m_stiffness; -}; - -/// -/// \class VolumeConstraint -/// -/// \brief -/// -class VolumeConstraint : public PbdConstraint -{ -public: - /// - /// \brief - /// - VolumeConstraint() : PbdConstraint(4) - {} - - /// - /// \brief - /// - Type getType() const - { - return Type::Volume; - } - - /// - /// \brief - /// - void initConstraint(PositionBasedModel& model, const unsigned int& pIdx1, const unsigned int& pIdx2, - const unsigned int& pIdx3, const unsigned int& pIdx4, const double k = 2.0 ); - - /// - /// \brief - /// - bool solvePositionConstraint(PositionBasedModel &model); - -public: - double m_restVolume; - double m_stiffness; -}; - -/// -/// \class FEMConstraint -/// -/// \brief The FEMConstraint class for constraint as the elastic energy -/// computed by linear shape functions with tetrahedral mesh. -/// We provide several model for elastic energy including: -/// Linear, Corrotation, St Venant-Kirchhof and NeoHookean -/// -class FEMConstraint : public PbdConstraint -{ -public: - enum class MaterialType - { - Linear, - Corotation, - StVK, - NeoHookean - } m_material; - - /// - /// \brief - /// - explicit FEMConstraint(const unsigned int nP, MaterialType mtype = MaterialType::StVK) : - PbdConstraint(nP) , m_material(mtype) - {} - -public: - double m_Volume; - Eigen::Matrix3d m_invRestMat; -}; - -/// -/// \class FEMTetConstraint -/// -/// \brief The FEMTetConstraint class class for constraint as the elastic energy -/// computed by linear shape functions with tetrahedral mesh. -/// -class FEMTetConstraint : public FEMConstraint -{ -public: - /// - /// \brief - /// - explicit FEMTetConstraint( MaterialType mtype = MaterialType::StVK) : - FEMConstraint(4, mtype) - {} - - /// - /// \brief - /// - Type getType() const - { - return Type::FEMTet; - } - - /// - /// \brief - /// - bool initConstraint(PositionBasedModel& model, const unsigned int& pIdx1, const unsigned int& pIdx2, - const unsigned int& pIdx3, const unsigned int& pIdx4); - - /// - /// \brief - /// - bool solvePositionConstraint(PositionBasedModel &model); -}; - -/// -/// \class FEMHexConstraint -/// -/// \brief The FEMHexConstraint class class for constraint as the elastic energy -/// computed by linear shape functions with hexahedral mesh. -/// -class FEMHexConstraint : public FEMConstraint -{ -public: - /// - /// \brief - /// - explicit FEMHexConstraint( MaterialType mtype = MaterialType::StVK) : - FEMConstraint(8, mtype) - {} - - /// - /// \brief - /// - Type getType() const - { - return Type::FEMHex; - } - - /// - /// \brief - /// - bool initConstraint(PositionBasedModel& model, const unsigned int& pIdx1, - const unsigned int& pIdx2, const unsigned int& pIdx3, - const unsigned int& pIdx4, const unsigned int& pIdx5, - const unsigned int& pIdx6, const unsigned int& pIdx7, - const unsigned int& pIdx8); - - /// - /// \brief - /// - bool solvePositionConstraint(PositionBasedModel &model); -}; - } -#endif // IMSTKPBDCONSTRAINT_H \ No newline at end of file +#endif // IMSTK_PBD_CONSTRAINT_H \ No newline at end of file diff --git a/Base/Constraint/imstkPbdDihedralConstraint.cpp b/Base/Constraint/imstkPbdDihedralConstraint.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0124f43623ad73b203ebec6b5a20ae9d63ecc98d --- /dev/null +++ b/Base/Constraint/imstkPbdDihedralConstraint.cpp @@ -0,0 +1,133 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + =========================================================================*/ + +#include "imstkPbdDihedralConstraint.h" +#include "imstkPbdModel.h" + +namespace imstk +{ + +void +DihedralConstraint::initConstraint(PositionBasedModel &model, + const unsigned int &pIdx1, const unsigned int &pIdx2, + const unsigned int &pIdx3, const unsigned int &pIdx4, + const double k) +{ + m_bodies[0] = pIdx1; + m_bodies[1] = pIdx2; + m_bodies[2] = pIdx3; + m_bodies[3] = pIdx4; + + m_stiffness = k; + auto state = model.getState(); + + const Vec3d &p0 = state->getInitialVertexPosition(pIdx1); + const Vec3d &p1 = state->getInitialVertexPosition(pIdx2); + const Vec3d &p2 = state->getInitialVertexPosition(pIdx3); + const Vec3d &p3 = state->getInitialVertexPosition(pIdx4); + + const Vec3d n1 = (p2 - p0).cross(p3 - p0).normalized(); + const Vec3d n2 = (p3 - p1).cross(p2 - p1).normalized(); + + m_restAngle = atan2(n1.cross(n2).dot(p3 - p2), (p3 - p2).norm()*n1.dot(n2)); +} + +bool +DihedralConstraint::solvePositionConstraint(PositionBasedModel& model) +{ + const unsigned int i1 = m_bodies[0]; + const unsigned int i2 = m_bodies[1]; + const unsigned int i3 = m_bodies[2]; + const unsigned int i4 = m_bodies[3]; + + auto state = model.getState(); + + Vec3d &p0 = state->getVertexPosition(i1); + Vec3d &p1 = state->getVertexPosition(i2); + Vec3d &p2 = state->getVertexPosition(i3); + Vec3d &p3 = state->getVertexPosition(i4); + + const double im0 = state->getInvMass(i1); + const double im1 = state->getInvMass(i2); + const double im2 = state->getInvMass(i3); + const double im3 = state->getInvMass(i4); + + if (im0 == 0.0 && im1 == 0.0) + { + return false; + } + + const Vec3d e = p3 - p2; + const Vec3d e1 = p3 - p0; + const Vec3d e2 = p0 - p2; + const Vec3d e3 = p3 - p1; + const Vec3d e4 = p1 - p2; + // To accelerate, all normal (area) vectors and edge length should be precomputed in parallel + Vec3d n1 = e1.cross(e); + Vec3d n2 = e.cross(e3); + const double A1 = n1.norm(); + const double A2 = n2.norm(); + n1 /= A1; + n2 /= A2; + + const double l = e.norm(); + if (l < EPS) + { + return false; + } + + const Vec3d grad0 = -(l / A1)*n1; + const Vec3d grad1 = -(l / A2)*n2; + const Vec3d grad2 = (e.dot(e1) / (A1*l))*n1 + (e.dot(e3) / (A2*l))*n2; + const Vec3d grad3 = (e.dot(e2) / (A1*l))*n1 + (e.dot(e4) / (A2*l))*n2; + + double lambda = im0*grad0.squaredNorm() + + im1*grad1.squaredNorm() + + im2*grad2.squaredNorm() + + im3*grad3.squaredNorm(); + + // huge difference if use acos instead of atan2 + lambda = (atan2(n1.cross(n2).dot(e), l*n1.dot(n2)) - m_restAngle) / lambda * m_stiffness; + + if (im0 > 0) + { + p0 += -im0*lambda*grad0; + } + + if (im1 > 0) + { + p1 += -im1*lambda*grad1; + } + + if (im2 > 0) + { + p2 += -im2*lambda*grad2; + } + + if (im3 > 0) + { + p3 += -im3*lambda*grad3; + } + + return true; +} + +} // imstk \ No newline at end of file diff --git a/Base/Constraint/imstkPbdDihedralConstraint.h b/Base/Constraint/imstkPbdDihedralConstraint.h new file mode 100644 index 0000000000000000000000000000000000000000..d44854ae0b2b5b0edbd0679a6af26f306f221c1c --- /dev/null +++ b/Base/Constraint/imstkPbdDihedralConstraint.h @@ -0,0 +1,78 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + =========================================================================*/ + +#ifndef IMSTK_PBD_DIHEDRAL_CONSTRAINT_H +#define IMSTK_PBD_DIHEDRAL_CONSTRAINT_H + +#include "imstkPbdConstraint.h" + +namespace imstk +{ + +/// +/// \class DihedralConstraint +/// +/// \brief Angular constraint between two triangular faces +/// +class DihedralConstraint : public PbdConstraint +{ +public: + /// + /// \brief Constructor + /// + DihedralConstraint() : PbdConstraint(4) {} + + /// + /// \brief Returns PBD constraint of type Type::Dihedral + /// + Type getType() const { return Type::Dihedral; } + + /// + /// \brief initConstraint + /// p3 + /// / | \ + /// / | \ + /// p0 | p1 + /// \ | / + /// \ | / + /// p2 + /// \param model + /// \param pIdx1 index of p0 + /// \param pIdx2 index of p1 + /// \param pIdx3 index of p2 + /// \param pIdx4 index of p3 + /// \param k stiffness + /// + void initConstraint(PositionBasedModel& model, const unsigned int& pIdx1, const unsigned int& pIdx2, + const unsigned int& pIdx3, const unsigned int& pIdx4, const double k = 1e-3); + + /// + /// \brief Solves the dihedral angular constraint + /// + bool solvePositionConstraint(PositionBasedModel &model); + +public: + double m_restAngle; ///> Rest angle + double m_stiffness; ///> Angular stiffness +}; +} + +#endif // IMSTK_PBD_DIHEDRAL_CONSTRAINT_H \ No newline at end of file diff --git a/Base/Constraint/imstkPbdDistanceConstraint.cpp b/Base/Constraint/imstkPbdDistanceConstraint.cpp new file mode 100644 index 0000000000000000000000000000000000000000..358f4ee9c0607e0d00cb68af528d8928705c8c0e --- /dev/null +++ b/Base/Constraint/imstkPbdDistanceConstraint.cpp @@ -0,0 +1,82 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + =========================================================================*/ + +#include "imstkPbdDistanceConstraint.h" +#include "imstkPbdModel.h" + +namespace imstk +{ + +void +DistanceConstraint::initConstraint(PositionBasedModel &model, const unsigned int &pIdx1, + const unsigned int &pIdx2, const double k) +{ + m_bodies[0] = pIdx1; + m_bodies[1] = pIdx2; + m_stiffness = k; + + auto state = model.getState(); + const Vec3d &p1 = state->getInitialVertexPosition(pIdx1); + const Vec3d &p2 = state->getInitialVertexPosition(pIdx2); + + m_restLength = (p1 - p2).norm(); +} + +bool +DistanceConstraint::solvePositionConstraint(PositionBasedModel &model) +{ + const unsigned int i1 = m_bodies[0]; + const unsigned int i2 = m_bodies[1]; + + auto state = model.getState(); + + Vec3d &p0 = state->getVertexPosition(i1); + Vec3d &p1 = state->getVertexPosition(i2); + + const double im1 = state->getInvMass(i1); + const double im2 = state->getInvMass(i2); + + const double wsum = im1 + im2; + + if (wsum == 0.0) + { + return false; + } + + Vec3d n = p1 - p0; + const double len = n.norm(); + n /= len; + + Vec3d gradC = m_stiffness*n*(len - m_restLength)/wsum; + + if (im1 > 0) + { + p0 += im1*gradC; + } + + if (im2 > 0) + { + p1 += -im2*gradC; + } + return true; +} + +} // imstk \ No newline at end of file diff --git a/Base/Constraint/imstkPbdDistanceConstraint.h b/Base/Constraint/imstkPbdDistanceConstraint.h new file mode 100644 index 0000000000000000000000000000000000000000..5df707cf455bf86ddaf1c7fa820ce529f965b880 --- /dev/null +++ b/Base/Constraint/imstkPbdDistanceConstraint.h @@ -0,0 +1,66 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + =========================================================================*/ + +#ifndef IMSTK_PBD_DISTANCE_CONSTRAINT_H +#define IMSTK_PBD_DISTANCE_CONSTRAINT_H + +#include "imstkPbdConstraint.h" + +namespace imstk +{ + +/// +/// \class DistanceConstraint +/// +/// \brief Distance constraints between two nodal points +/// +class DistanceConstraint : public PbdConstraint +{ +public: + /// + /// \brief Constructor + /// + DistanceConstraint() : PbdConstraint(2) {} + + /// + /// \brief Returns PBD constraint of type Type::Distance + /// + Type getType() const { return Type::Distance; } + + /// + /// \brief Initializes the distance constraint + /// + void initConstraint(PositionBasedModel& model, const unsigned int& pIdx1, + const unsigned int& pIdx2, const double k = 1e-1); + + /// + /// \brief Solves the Distance constraint + /// + bool solvePositionConstraint(PositionBasedModel &model); + +public: + double m_restLength; ///> Rest length between the nodes + double m_stiffness; ///> Stiffness of the constaint +}; + +} + +#endif // IMSTK_PBD_DISTANCE_CONSTRAINT_H \ No newline at end of file diff --git a/Base/Constraint/imstkPbdFEHexConstraint.h b/Base/Constraint/imstkPbdFEHexConstraint.h new file mode 100644 index 0000000000000000000000000000000000000000..6c8c22f7393e465775f4b1f36fe2dc9cb6298819 --- /dev/null +++ b/Base/Constraint/imstkPbdFEHexConstraint.h @@ -0,0 +1,70 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + =========================================================================*/ + +#ifndef IMSTK_PBD_FE_HEX_CONSTRAINT_H +#define IMSTK_PBD_FE_HEX_CONSTRAINT_H + +#include "imstkPbdFEMConstraint.h" + +namespace imstk +{ + +/// +/// \class FEMHexConstraint +/// +/// \brief The FEMHexConstraint class class for constraint as the elastic energy +/// computed by linear shape functions with hexahedral mesh. +/// +class FEMHexConstraint : public FEMConstraint +{ +public: + /// + /// \brief Constructor + /// + explicit FEMHexConstraint(MaterialType mtype = MaterialType::StVK) : + FEMConstraint(8, mtype) {} + + /// + /// \brief Get the type of FEM constraint + /// + Type getType() const + { + return Type::FEMHex; + } + + /// + /// \brief Initializes the FEM hexahedral element constraint + /// + bool initConstraint(PositionBasedModel& model, const unsigned int& pIdx1, + const unsigned int& pIdx2, const unsigned int& pIdx3, + const unsigned int& pIdx4, const unsigned int& pIdx5, + const unsigned int& pIdx6, const unsigned int& pIdx7, + const unsigned int& pIdx8); + + /// + /// \brief Solves the FEM hexahedral element constraint + /// + bool solvePositionConstraint(PositionBasedModel &model); +}; + +} + +#endif // IMSTK_PBD_FE_HEX_CONSTRAINT_H \ No newline at end of file diff --git a/Base/Constraint/imstkPbdFEMConstraint.h b/Base/Constraint/imstkPbdFEMConstraint.h new file mode 100644 index 0000000000000000000000000000000000000000..ef6e7185ccd423cb5c48f1b65ec4de24ee783fe2 --- /dev/null +++ b/Base/Constraint/imstkPbdFEMConstraint.h @@ -0,0 +1,64 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + =========================================================================*/ + +#ifndef IMSTK_PBD_FEM_CONSTRAINT_H +#define IMSTK_PBD_FEM_CONSTRAINT_H + +#include "imstkPbdConstraint.h" + +namespace imstk +{ + +/// +/// \class FEMConstraint +/// +/// \brief The FEMConstraint class for constraint as the elastic energy +/// computed by linear shape functions with tetrahedral mesh. +/// We provide several model for elastic energy including: +/// Linear, Co-rotation, St Venant-Kirchhof and NeoHookean +/// +class FEMConstraint : public PbdConstraint +{ +public: + // Material type + enum class MaterialType + { + Linear, + Corotation, + StVK, + NeoHookean + }; + + /// + /// \brief + /// + explicit FEMConstraint(const unsigned int nP, MaterialType mtype = MaterialType::StVK) : + PbdConstraint(nP), m_material(mtype) {} + +public: + double m_Volume; + MaterialType m_material; + Mat3d m_invRestMat; +}; + +} + +#endif // IMSTK_PBD_FEM_CONSTRAINT_H \ No newline at end of file diff --git a/Base/Constraint/imstkPbdFETetConstraint.cpp b/Base/Constraint/imstkPbdFETetConstraint.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2ba201e7c404dab76d5cc6c874694823c1287fe7 --- /dev/null +++ b/Base/Constraint/imstkPbdFETetConstraint.cpp @@ -0,0 +1,223 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + =========================================================================*/ + +#include "imstkPbdFETetConstraint.h" +#include "imstkPbdModel.h" + +namespace imstk +{ + +bool +FEMTetConstraint::initConstraint(PositionBasedModel &model, + const unsigned int &pIdx1, const unsigned int &pIdx2, + const unsigned int &pIdx3, const unsigned int &pIdx4) +{ + m_bodies[0] = pIdx1; + m_bodies[1] = pIdx2; + m_bodies[2] = pIdx3; + m_bodies[3] = pIdx4; + + auto state = model.getState(); + + const Vec3d &p0 = state->getInitialVertexPosition(pIdx1); + const Vec3d &p1 = state->getInitialVertexPosition(pIdx2); + const Vec3d &p2 = state->getInitialVertexPosition(pIdx3); + const Vec3d &p3 = state->getInitialVertexPosition(pIdx4); + + m_Volume = (1.0 / 6.0) * (p3 - p0).dot((p1 - p0).cross(p2 - p0)); + + Mat3d m; + m.col(0) = p0 - p3; + m.col(1) = p1 - p3; + m.col(2) = p2 - p3; + + const double det = m.determinant(); + if (fabs(det) > EPS) + { + m_invRestMat = m.inverse(); + return true; + } + + return false; +} + +bool +FEMTetConstraint::solvePositionConstraint(PositionBasedModel &model) +{ + const unsigned int i1 = m_bodies[0]; + const unsigned int i2 = m_bodies[1]; + const unsigned int i3 = m_bodies[2]; + const unsigned int i4 = m_bodies[3]; + + auto state = model.getState(); + + Vec3d &p0 = state->getVertexPosition(i1); + Vec3d &p1 = state->getVertexPosition(i2); + Vec3d &p2 = state->getVertexPosition(i3); + Vec3d &p3 = state->getVertexPosition(i4); + + //double currentVolume = (1.0 / 6.0) * (p3 - p0).dot((p1 - p0).cross(p2 - p0)); + + Mat3d m; + m.col(0) = p0 - p3; + m.col(1) = p1 - p3; + m.col(2) = p2 - p3; + + // deformation gradient + const Mat3d F = m*m_invRestMat; + // First Piola-Kirchhoff tensor + Mat3d P; + // energy constraint + double C = 0; + + const double mu = model.getFirstLame(); + const double lambda = model.getSecondLame(); + + switch (m_material) + { + + // P(F) = F*(2*mu*E + lambda*tr(E)*I) + // E = (F^T*F - I)/2 + case MaterialType::StVK: + { + Mat3d E; + E(0, 0) = 0.5*(F(0, 0) * F(0, 0) + F(1, 0) * F(1, 0) + F(2, 0) * F(2, 0) - 1.0); // xx + E(1, 1) = 0.5*(F(0, 1) * F(0, 1) + F(1, 1) * F(1, 1) + F(2, 1) * F(2, 1) - 1.0); // yy + E(2, 2) = 0.5*(F(0, 2) * F(0, 2) + F(1, 2) * F(1, 2) + F(2, 2) * F(2, 2) - 1.0); // zz + E(0, 1) = 0.5*(F(0, 0) * F(0, 1) + F(1, 0) * F(1, 1) + F(2, 0) * F(2, 1)); // xy + E(0, 2) = 0.5*(F(0, 0) * F(0, 2) + F(1, 0) * F(1, 2) + F(2, 0) * F(2, 2)); // xz + E(1, 2) = 0.5*(F(0, 1) * F(0, 2) + F(1, 1) * F(1, 2) + F(2, 1) * F(2, 2)); // yz + E(1, 0) = E(0, 1); + E(2, 0) = E(0, 2); + E(2, 1) = E(1, 2); + + P = 2 * mu*E; + double tr = E.trace(); + double lt = lambda*tr; + P(0, 0) += lt; + P(1, 1) += lt; + P(2, 2) += lt; + P = F*P; + + C = E(0, 0)*E(0, 0) + E(0, 1)*E(0, 1) + E(0, 2)*E(0, 2) + + E(1, 0)*E(1, 0) + E(1, 1)*E(1, 1) + E(1, 2)*E(1, 2) + + E(2, 0)*E(2, 0) + E(2, 1)*E(2, 1) + E(2, 2)*E(2, 2); + C = mu*C + 0.5*lambda*tr*tr; + + break; + } + + // P(F) = (2*mu*(F-R) + lambda*(J-1)*J*F^-T + case MaterialType::Corotation: + { + Eigen::JacobiSVD<Mat3d> svd(F, Eigen::ComputeFullU | Eigen::ComputeFullV); + Mat3d R = svd.matrixU()*svd.matrixV().adjoint(); + Vec3d Sigma(svd.singularValues()); + Mat3d invFT = svd.matrixU(); + invFT.col(0) /= Sigma(0); + invFT.col(1) /= Sigma(1); + invFT.col(2) /= Sigma(2); + invFT *= svd.matrixV().adjoint(); + double J = Sigma(0)*Sigma(1)*Sigma(2); + Mat3d FR = F - R; + + P = 2 * mu*FR + lambda*(J - 1)*J*invFT; + + C = FR(0, 0)*FR(0, 0) + FR(0, 1)*FR(0, 1) + FR(0, 2)*FR(0, 2) + + FR(1, 0)*FR(1, 0) + FR(1, 1)*FR(1, 1) + FR(1, 2)*FR(1, 2) + + FR(2, 0)*FR(2, 0) + FR(2, 1)*FR(2, 1) + FR(2, 2)*FR(2, 2); + C = mu*C + 0.5*lambda*(J - 1)*(J - 1); + + break; + } + // P(F) = mu*(F - mu*F^-T) + lambda*log(J)F^-T; + case MaterialType::NeoHookean: + { + Mat3d invFT = F.inverse().transpose(); + double logJ = log(F.determinant()); + P = mu*(F - invFT) + lambda*logJ*invFT; + + C = F(0, 0)*F(0, 0) + F(0, 1)*F(0, 1) + F(0, 2)*F(0, 2) + + F(1, 0)*F(1, 0) + F(1, 1)*F(1, 1) + F(1, 2)*F(1, 2) + + F(2, 0)*F(2, 0) + F(2, 1)*F(2, 1) + F(2, 2)*F(2, 2); + + C = 0.5*mu*(C - 3) - mu*logJ + 0.5*lambda*logJ*logJ; + + break; + } + + case MaterialType::Linear: + { + break; + } + + default: + { + LOG(WARNING) << "Material type not supported ! \n"; + break; + } + } + + const double im1 = state->getInvMass(i1); + const double im2 = state->getInvMass(i2); + const double im3 = state->getInvMass(i3); + const double im4 = state->getInvMass(i4); + + Mat3d gradC = m_Volume*P*m_invRestMat.transpose(); + + double sum = im1*gradC.col(0).squaredNorm() + + im2*gradC.col(1).squaredNorm() + + im3*gradC.col(2).squaredNorm() + + im4*(gradC.col(0) + gradC.col(1) + gradC.col(2)).squaredNorm(); + + if (sum < EPS) + { + return false; + } + + C = C*m_Volume; + + const double s = C / sum; + + if (im1 > 0) + { + p0 += -s*im1*gradC.col(0); + } + + if (im2 > 0) + { + p1 += -s*im2*gradC.col(1); + } + + if (im3 > 0) + { + p2 += -s*im3*gradC.col(2); + } + + if (im4 > 0) + { + p3 += s*im4*(gradC.col(0) + gradC.col(1) + gradC.col(2)); + } + + return true; +} + +} // imstk \ No newline at end of file diff --git a/Base/Constraint/imstkPbdFETetConstraint.h b/Base/Constraint/imstkPbdFETetConstraint.h new file mode 100644 index 0000000000000000000000000000000000000000..df3e0261b47377f03bf02774e18dfe3a134d3ea1 --- /dev/null +++ b/Base/Constraint/imstkPbdFETetConstraint.h @@ -0,0 +1,67 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + =========================================================================*/ + +#ifndef IMSTK_PBD_FE_TET_CONSTRAINT_H +#define IMSTK_PBD_FE_TET_CONSTRAINT_H + +#include "imstkPbdFEMConstraint.h" + +namespace imstk +{ + +/// +/// \class FEMTetConstraint +/// +/// \brief The FEMTetConstraint class class for constraint as the elastic energy +/// computed by linear shape functions with tetrahedral mesh. +/// +class FEMTetConstraint : public FEMConstraint +{ +public: + /// + /// \brief Constructor + /// + explicit FEMTetConstraint(MaterialType mtype = MaterialType::StVK) : + FEMConstraint(4, mtype) {} + + /// + /// \brief Get the type of FEM constraint + /// + Type getType() const + { + return Type::FEMTet; + } + + /// + /// \brief Initialize the tetrahedral FEM constraint + /// + bool initConstraint(PositionBasedModel& model, const unsigned int& pIdx1, const unsigned int& pIdx2, + const unsigned int& pIdx3, const unsigned int& pIdx4); + + /// + /// \brief Solve the tetrahedral FEM constraint + /// + bool solvePositionConstraint(PositionBasedModel &model); +}; + +} + +#endif // IMSTK_PBD_FE_TET_CONSTRAINT_H \ No newline at end of file diff --git a/Base/Constraint/imstkPbdVolumeConstraint.cpp b/Base/Constraint/imstkPbdVolumeConstraint.cpp new file mode 100644 index 0000000000000000000000000000000000000000..206ef643234b4a129f8cd3fb6c1cfd219b143ea9 --- /dev/null +++ b/Base/Constraint/imstkPbdVolumeConstraint.cpp @@ -0,0 +1,109 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + =========================================================================*/ + +#include "imstkPbdVolumeConstraint.h" +#include "imstkPbdModel.h" + +namespace imstk +{ + +void +VolumeConstraint::initConstraint(PositionBasedModel &model, const unsigned int &pIdx1, + const unsigned int &pIdx2, const unsigned int &pIdx3, + const unsigned int &pIdx4, const double k) +{ + m_bodies[0] = pIdx1; + m_bodies[1] = pIdx2; + m_bodies[2] = pIdx3; + m_bodies[3] = pIdx4; + + m_stiffness = k; + + auto state = model.getState(); + + const Vec3d &p0 = state->getInitialVertexPosition(pIdx1); + const Vec3d &p1 = state->getInitialVertexPosition(pIdx2); + const Vec3d &p2 = state->getInitialVertexPosition(pIdx3); + const Vec3d &p3 = state->getInitialVertexPosition(pIdx4); + + m_restVolume = (1.0 / 6.0)*((p1 - p0).cross(p2 - p0)).dot(p3 - p0); +} + +bool +VolumeConstraint::solvePositionConstraint(PositionBasedModel &model) +{ + const unsigned int i1 = m_bodies[0]; + const unsigned int i2 = m_bodies[1]; + const unsigned int i3 = m_bodies[2]; + const unsigned int i4 = m_bodies[3]; + + auto state = model.getState(); + + Vec3d &x1 = state->getVertexPosition(i1); + Vec3d &x2 = state->getVertexPosition(i2); + Vec3d &x3 = state->getVertexPosition(i3); + Vec3d &x4 = state->getVertexPosition(i4); + + const double im1 = state->getInvMass(i1); + const double im2 = state->getInvMass(i2); + const double im3 = state->getInvMass(i3); + const double im4 = state->getInvMass(i4); + + const double onesixth = 1.0 / 6.0; + + const Vec3d grad1 = onesixth*(x2 - x3).cross(x4 - x2); + const Vec3d grad2 = onesixth*(x3 - x1).cross(x4 - x1); + const Vec3d grad3 = onesixth*(x4 - x1).cross(x2 - x1); + const Vec3d grad4 = onesixth*(x2 - x1).cross(x3 - x1); + + const double V = grad4.dot(x4 - x1); + + double lambda = im1*grad1.squaredNorm() + + im2*grad2.squaredNorm() + + im3*grad3.squaredNorm() + + im4*grad4.squaredNorm(); + + lambda = (V - m_restVolume) / lambda * m_stiffness; + + if (im1 > 0) + { + x1 += -im1*lambda*grad1; + } + + if (im1 > 0) + { + x2 += -im2*lambda*grad2; + } + + if (im3 > 0) + { + x3 += -im3*lambda*grad3; + } + + if (im4 > 0) + { + x4 += -im4*lambda*grad4; + } + + return true; +} + +} // imstk \ No newline at end of file diff --git a/Base/Constraint/imstkPbdVolumeConstraint.h b/Base/Constraint/imstkPbdVolumeConstraint.h new file mode 100644 index 0000000000000000000000000000000000000000..efb1d731ab6ad11eb05f11c857ef9cc90a0c297f --- /dev/null +++ b/Base/Constraint/imstkPbdVolumeConstraint.h @@ -0,0 +1,69 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + =========================================================================*/ + +#ifndef IMSTK_PBD_VOLUME_CONSTRAINT_H +#define IMSTK_PBD_VOLUME_CONSTRAINT_H + +#include "imstkPbdConstraint.h" + +namespace imstk +{ + +/// +/// \class VolumeConstraint +/// +/// \brief Volume constraint for tetrahedral element +/// +class VolumeConstraint : public PbdConstraint +{ +public: + /// + /// \brief constructor + /// + VolumeConstraint() : PbdConstraint(4) {} + + /// + /// \brief Returns PBD constraint of type Type::Volume + /// + Type getType() const + { + return Type::Volume; + } + + /// + /// \brief Initializes the volume constraint + /// + void initConstraint(PositionBasedModel& model, const unsigned int& pIdx1, const unsigned int& pIdx2, + const unsigned int& pIdx3, const unsigned int& pIdx4, const double k = 2.0); + + /// + /// \brief Solves the volume constraint + /// + bool solvePositionConstraint(PositionBasedModel &model); + +public: + double m_restVolume; ///> Rest volume + double m_stiffness; ///> Stiffness of the volume constraint +}; + +} + +#endif // IMSTK_PBD_DISTANCE_CONSTRAINT_H \ No newline at end of file diff --git a/Base/SceneElements/Objects/imstkPbdModel.cpp b/Base/SceneElements/Objects/imstkPbdModel.cpp index 8b72205f097780ec3e6c585f3fbe159b24db0951..2e250a1bbf7060e0372dd58372b4420ff66dd0e3 100644 --- a/Base/SceneElements/Objects/imstkPbdModel.cpp +++ b/Base/SceneElements/Objects/imstkPbdModel.cpp @@ -1,6 +1,12 @@ #include "imstkPbdModel.h" #include "imstkTetrahedralMesh.h" #include "imstkSurfaceMesh.h" +#include "imstkPbdVolumeConstraint.h" +#include "imstkPbdDistanceConstraint.h" +#include "imstkPbdDihedralConstraint.h" +#include "imstkPbdAreaConstraint.h" +#include "imstkPbdFETetConstraint.h" +#include "imstkPbdFEHexConstraint.h" #include <g3log/g3log.hpp> diff --git a/Base/SceneElements/Objects/imstkPbdModel.h b/Base/SceneElements/Objects/imstkPbdModel.h index 5226a792f98238dce2c3910b17cad8c5519f8fd7..5356e6acc804d965797357e84d8cfade26e72c71 100644 --- a/Base/SceneElements/Objects/imstkPbdModel.h +++ b/Base/SceneElements/Objects/imstkPbdModel.h @@ -5,6 +5,7 @@ #include <Eigen/Dense> #include "imstkPbdConstraint.h" +#include "imstkPbdFEMConstraint.h" #include "imstkPbdState.h" namespace imstk diff --git a/Examples/Sandbox/main.cpp b/Examples/Sandbox/main.cpp index 79b5700e75affcb9db834bd5013b14425f981a7f..2139a8b11a455bc686ac26e13d814281909401a9 100644 --- a/Examples/Sandbox/main.cpp +++ b/Examples/Sandbox/main.cpp @@ -104,7 +104,7 @@ int main() //testMultiTextures(); //testMeshCCD(); - testPenaltyRigidCollision(); + //testPenaltyRigidCollision(); //testTwoFalcons(); //testObjectController(); //testCameraController(); @@ -123,7 +123,7 @@ int main() //testTwoOmnis(); //testVectorPlotters(); //testPbdVolume(); - //testPbdCloth(); + testPbdCloth(); // int n; // std::cout << "testPbdCollision(): 1" << std::endl; @@ -1266,7 +1266,7 @@ void testPbdCloth() /*Constraint configuration*/"Dihedral 0.001", /*Mass*/1.0, /*Gravity*/"0 -9.8 0", - /*TimeStep*/0.001, + /*TimeStep*/0.01, /*FixedPoint*/"1 20", /*NumberOfIterationInConstraintSolver*/5 ); @@ -1321,7 +1321,7 @@ void testPbdCollision() deformableObj->setCollidingGeometry(surfMesh); deformableObj->setPhysicsGeometry(volTetMesh); deformableObj->setPhysicsToCollidingMap(deformMapP2C); - deformableObj->setPhysicsToVisualMap(deformMapP2V); + deformableObj->setPhysicsToVisualMap(deformMapP2V); deformableObj->setCollidingToVisualMap(deformMapC2V); deformableObj->init(/*Number of Constraints*/1, /*Constraint configuration*/"FEM NeoHookean 1.0 0.3", @@ -1446,7 +1446,7 @@ void testPbdCollision() volTetMesh1->extractSurfaceMesh(surfMesh1); volTetMesh1->extractSurfaceMesh(surfMeshVisual1); - + auto deformMapP2V1 = std::make_shared<imstk::OneToOneMap>(); deformMapP2V1->setMaster(volTetMesh1); @@ -1468,7 +1468,7 @@ void testPbdCollision() deformableObj1->setCollidingGeometry(surfMesh1); deformableObj1->setPhysicsGeometry(volTetMesh1); deformableObj1->setPhysicsToCollidingMap(deformMapP2C1); - deformableObj1->setPhysicsToVisualMap(deformMapP2V1); + deformableObj1->setPhysicsToVisualMap(deformMapP2V1); deformableObj1->setCollidingToVisualMap(deformMapC2V1); deformableObj1->init(/*Number of Constraints*/1, /*Constraint configuration*/"FEM NeoHookean 10.0 0.5", @@ -1491,7 +1491,7 @@ void testPbdCollision() } else{ // floor - + std::vector<imstk::Vec3d> vertList; double width = 100.0; double height = 100.0; @@ -1717,7 +1717,7 @@ void testLineMesh() scene->addSceneObject(blade); } - + if (clothTest){