diff --git a/Base/Geometry/imstkCube.cpp b/Base/Geometry/imstkCube.cpp index 1971889ca05361701e420d8cdec7dfbec553ca6c..afa243e58bbdb7e1343ff7db128a8dcaa39fef2b 100644 --- a/Base/Geometry/imstkCube.cpp +++ b/Base/Geometry/imstkCube.cpp @@ -22,6 +22,7 @@ #include "imstkCube.h" namespace imstk { + const double& Cube::getWidth() const { @@ -33,4 +34,11 @@ Cube::setWidth(const double& width) { m_width = width; } + +double +Cube::getVolume() const +{ + return m_width*m_width; +} + } diff --git a/Base/Geometry/imstkCube.h b/Base/Geometry/imstkCube.h index 34336c9a0e6b01fd8b74bddebab57e1b47a1aa20..60dacfdc38e855b52f45dd7ae94af7941aa0ebbc 100644 --- a/Base/Geometry/imstkCube.h +++ b/Base/Geometry/imstkCube.h @@ -42,6 +42,7 @@ public: const double& getWidth() const; void setWidth(const double& width); + double getVolume() const; protected: double m_width; diff --git a/Base/Geometry/imstkGeometry.cpp b/Base/Geometry/imstkGeometry.cpp index f2b190378d4db4bc884916840cc3db709e9fc0e0..1a55e84a4e19cd8afbaad0739b8a83cab34c1900 100644 --- a/Base/Geometry/imstkGeometry.cpp +++ b/Base/Geometry/imstkGeometry.cpp @@ -22,6 +22,7 @@ #include "imstkGeometry.h" namespace imstk { + void Geometry::translate(const Vec3d& t) { diff --git a/Base/Geometry/imstkGeometry.h b/Base/Geometry/imstkGeometry.h index bfc81ca1d2a3130defacbb2ab23953b1e57a2d58..63f8941b51d6e79fe73ceee6920cf92b1a97463c 100644 --- a/Base/Geometry/imstkGeometry.h +++ b/Base/Geometry/imstkGeometry.h @@ -22,6 +22,7 @@ #ifndef imstkGeometry_h #define imstkGeometry_h +#include "g3log/g3log.hpp" #include "imstkMath.h" namespace imstk { @@ -71,6 +72,8 @@ public: const GeometryType& getType() const; + virtual double getVolume() const = 0; + protected: Geometry(GeometryType type, diff --git a/Base/Geometry/imstkGeometryMap.cpp b/Base/Geometry/imstkGeometryMap.cpp index ebc60e13d9bc60bd1d3440e46d91f6a369c53cb6..8dfc9d891f788e8b3f0e688624909b28bb89cb49 100644 --- a/Base/Geometry/imstkGeometryMap.cpp +++ b/Base/Geometry/imstkGeometryMap.cpp @@ -22,43 +22,52 @@ #include "imstkGeometryMap.h" namespace imstk { - void GeometryMap::muteMap() - { - m_isActive = false; - } - - void GeometryMap::activateMap() - { - m_isActive = true; - } - - const GeometryMapType& GeometryMap::getType() const - { - return m_type; - } - - void GeometryMap::setMaster(std::shared_ptr<Geometry> master) - { - m_master = master; - } - - std::shared_ptr<Geometry> GeometryMap::getMaster() const - { - return m_master; - } - - void GeometryMap::setSlave(std::shared_ptr<Geometry> slave) - { - m_slave = slave; - } - - std::shared_ptr<Geometry> GeometryMap::getSlave() const - { - return m_slave; - } - - bool GeometryMap::isActive() const - { - return m_isActive; - } + +void +GeometryMap::muteMap() +{ + m_isActive = false; +} + +void +GeometryMap::activateMap() +{ + m_isActive = true; +} + +const +GeometryMapType& GeometryMap::getType() const +{ + return m_type; +} + +void +GeometryMap::setMaster(std::shared_ptr<Geometry> master) +{ + m_master = master; +} + +std::shared_ptr<Geometry> +GeometryMap::getMaster() const +{ + return m_master; +} + +void +GeometryMap::setSlave(std::shared_ptr<Geometry> slave) +{ + m_slave = slave; +} + +std::shared_ptr<Geometry> +GeometryMap::getSlave() const +{ + return m_slave; +} + +bool +GeometryMap::isActive() const +{ + return m_isActive; +} } \ No newline at end of file diff --git a/Base/Geometry/imstkGeometryMap.h b/Base/Geometry/imstkGeometryMap.h index 335bb5807354c1fdf01bf2f052c780a17f7d771e..134f3e58a2103ce4b8325f39289106721b498718 100644 --- a/Base/Geometry/imstkGeometryMap.h +++ b/Base/Geometry/imstkGeometryMap.h @@ -68,10 +68,10 @@ public: const GeometryMapType& getType() const; virtual void setMaster(std::shared_ptr<Geometry> master); - std::shared_ptr<Geometry> getMaster() const; + virtual std::shared_ptr<Geometry> getMaster() const; virtual void setSlave(std::shared_ptr<Geometry> slave); - std::shared_ptr<Geometry> getSlave() const; + virtual std::shared_ptr<Geometry> getSlave() const; /// /// \brief Returns true if the map is actively applied at runtime, else false. diff --git a/Base/Geometry/imstkHexahedralMesh.cpp b/Base/Geometry/imstkHexahedralMesh.cpp index 86ba2fd506bf5ebc65aa4e9412743dc5487d00ce..16f252d5769b1802df5c5c140bd7d51fbf2998a2 100644 --- a/Base/Geometry/imstkHexahedralMesh.cpp +++ b/Base/Geometry/imstkHexahedralMesh.cpp @@ -22,15 +22,77 @@ #include "imstkHexahedralMesh.h" namespace imstk { + const std::vector<HexahedralMesh::HexaArray>& -HexahedralMesh::getHexahedronVertices() const +HexahedralMesh::getHexahedronMeshVertices() const { return m_hexahedronVertices; } void -HexahedralMesh::setHexahedronVertices(const std::vector<HexaArray>& hexahedrons) +HexahedralMesh::setHexahedronMeshVertices(const std::vector<HexaArray>& hexahedrons) { m_hexahedronVertices = hexahedrons; } + + +const imstk::HexahedralMesh::HexaArray& +HexahedralMesh::getHexahedronVertices(const int hexaNum) const +{ + return m_hexahedronVertices.at(hexaNum); +} + +int +HexahedralMesh::getNumHexahedra() const +{ + return m_hexahedronVertices.size(); +} + +double +HexahedralMesh::getVolume() const +{ + double volume = 0.0; + imstk::Vec3d v[8]; + imstk::Vec3d a, b, c; + imstk::Mat3d A; + for (int i = 0; i < getNumHexahedra(); ++i) + { + auto hexVerts = getHexahedronVertices(i); + for (int i = 0; i < 8; ++i) + { + v[i] = getVertexPosition(hexVerts[i]); + } + + a = v[7] - v[0]; + b = v[1] - v[0]; + c = v[3] - v[5]; + + A << a[0], b[0], c[0], + a[1], b[1], c[1], + a[2], b[2], c[2]; + + volume += A.determinant(); + + b = v[4] - v[0]; + c = v[5] - v[6]; + + A << a[0], b[0], c[0], + a[1], b[1], c[1], + a[2], b[2], c[2]; + + volume += A.determinant(); + + b = v[2] - v[0]; + c = v[6] - v[3]; + + A << a[0], b[0], c[0], + a[1], b[1], c[1], + a[2], b[2], c[2]; + + volume += A.determinant(); + } + + return volume/6; +} + } diff --git a/Base/Geometry/imstkHexahedralMesh.h b/Base/Geometry/imstkHexahedralMesh.h index dea35888dd7f79aeed36cc02e7da61e9436d7481..9a29b65a76be7929e80c23c0d1a54ffbfb584c18 100644 --- a/Base/Geometry/imstkHexahedralMesh.h +++ b/Base/Geometry/imstkHexahedralMesh.h @@ -37,8 +37,16 @@ public: ~HexahedralMesh() = default; - const std::vector<HexaArray>& getHexahedronVertices() const; - void setHexahedronVertices(const std::vector<HexaArray>& hexahedrons); + const std::vector<HexaArray>& getHexahedronMeshVertices() const; + void setHexahedronMeshVertices(const std::vector<HexaArray>& hexahedrons); + + const imstk::HexahedralMesh::HexaArray& getHexahedronVertices(const int hexaNum) const; + int getNumHexahedra() const; + + /// + /// \brief Get the total volume of the hexahedral mesh + /// + double getVolume() const; protected: diff --git a/Base/Geometry/imstkIdentityMap.cpp b/Base/Geometry/imstkIdentityMap.cpp index 18afe8b9239b927035a51a901ddb58775c5a7e4e..fd3e6155c4cf20932755ae5190546a315061795a 100644 --- a/Base/Geometry/imstkIdentityMap.cpp +++ b/Base/Geometry/imstkIdentityMap.cpp @@ -23,24 +23,27 @@ namespace imstk { - const imstk::RigidTransform3d& IdentityMap::getTransform() const +const imstk::RigidTransform3d& +IdentityMap::getTransform() const +{ + return imstk::RigidTransform3d::Identity(); +} + +void +IdentityMap::applyMap() +{ + if (m_isActive) { - return imstk::RigidTransform3d::Identity(); - } - - void IdentityMap::applyMap() - { - if (m_isActive) + if (!m_master || !m_slave) { - if (!m_master || !m_slave) - { - LOG(WARNING) << "Identity map is being applied without valid geometries\n"; - return; - } - - // Set the follower mesh configuration to be same as that of master - m_slave->setPosition(m_master->getPosition()); - m_slave->setOrientation(m_master->getOrientation()); + LOG(WARNING) << "Identity map is being applied without valid geometries\n"; + return; } + + // Set the follower mesh configuration to be same as that of master + m_slave->setPosition(m_master->getPosition()); + m_slave->setOrientation(m_master->getOrientation()); } +} + } \ No newline at end of file diff --git a/Base/Geometry/imstkIsometricMap.cpp b/Base/Geometry/imstkIsometricMap.cpp index 2663f0ef6510913bd612c0f335d716776fd8ba83..c8a67a862a2d72b9a789ddfd462fd6bb271e1316 100644 --- a/Base/Geometry/imstkIsometricMap.cpp +++ b/Base/Geometry/imstkIsometricMap.cpp @@ -21,32 +21,37 @@ #include "imstkIsometricMap.h" namespace imstk { - void IsometricMap::setTransform(const RigidTransform3d& affineTransform) - { - m_rigidTransform = affineTransform; - } - - const imstk::RigidTransform3d& IsometricMap::getTransform() const - { - return m_rigidTransform; - } - void IsometricMap::applyMap() +void +IsometricMap::setTransform(const RigidTransform3d& affineTransform) +{ + m_rigidTransform = affineTransform; +} + +const imstk::RigidTransform3d& +IsometricMap::getTransform() const +{ + return m_rigidTransform; +} + +void +IsometricMap::applyMap() +{ + if (m_isActive) { - if (m_isActive) + if (!m_master || !m_slave) { - if (!m_master || !m_slave) - { - //LOG(WARNING) << "Isometric map is being applied without valid geometries\n"; - return; - } - - // First set the follower mesh configuration to that of master - m_slave->setPosition(m_master->getPosition()); - m_slave->setOrientation(m_master->getOrientation()); - - // Now, apply the offset transform - m_slave->transform(m_rigidTransform); + LOG(WARNING) << "Isometric map is being applied without valid geometries\n"; + return; } + + // First set the follower mesh configuration to that of master + m_slave->setPosition(m_master->getPosition()); + m_slave->setOrientation(m_master->getOrientation()); + + // Now, apply the offset transform + m_slave->transform(m_rigidTransform); } +} + } \ No newline at end of file diff --git a/Base/Geometry/imstkMesh.cpp b/Base/Geometry/imstkMesh.cpp index 441246e4f6997b9f2bec93bce48ecad2c9fdb7bf..7c76a302afc520030ffade0c7a40e52d375e32fd 100644 --- a/Base/Geometry/imstkMesh.cpp +++ b/Base/Geometry/imstkMesh.cpp @@ -28,6 +28,11 @@ Mesh::getInitialVertexPositions() const return m_initialVertexPositions; } +const imstk::Vec3d& Mesh::getInitialVertexPosition(const int vertNum) const +{ + return m_initialVertexPositions.at(vertNum); +} + void Mesh::setInitialVertexPositions(const std::vector<Vec3d>& vertices) { @@ -46,6 +51,16 @@ Mesh::setVertexPositions(const std::vector<Vec3d>& vertices) m_vertexPositions = vertices; } +const imstk::Vec3d& Mesh::getVertexPosition(const int vertNum) const +{ + return m_vertexPositions.at(vertNum); +} + +void Mesh::setVertexPosition(const int vertNum, const imstk::Vec3d& pos) +{ + m_vertexPositions.at(vertNum) = pos; +} + const std::vector<Vec3d>& Mesh::getVertexDisplacements() const { @@ -57,4 +72,46 @@ Mesh::setVertexDisplacements(const std::vector<Vec3d>& diff) { m_vertexDisplacements = diff; } + +const imstk::Vec3d& Mesh::getVertexDisplacement(const int vertNum) const +{ + return m_vertexDisplacements.at(vertNum); +} + +int Mesh::getNumVertices() const +{ + return m_initialVertexPositions.size(); +} + +void Mesh::computeBoundingBox(imstk::Vec3d& min, imstk::Vec3d& max, const double percent) const +{ + min = imstk::Vec3d(std::numeric_limits<double>::max(), + std::numeric_limits<double>::max(), + std::numeric_limits<double>::max()); + + max = imstk::Vec3d(std::numeric_limits<double>::min(), + std::numeric_limits<double>::min(), + std::numeric_limits<double>::min()); + + for (auto it = m_vertexPositions.begin(); it != m_vertexPositions.end(); ++it) + { + for (int i = 0; i < 3; ++i) + { + min[i] = std::min(min[i], (*it)[i]); + max[i] = std::max(max[i], (*it)[i]); + } + } + + if (percent == 0.0) + { + return; + } + else + { + imstk::Vec3d range = max - min; + min = min - range*(percent / 100); + max = max + range*(percent / 100); + } +} + } diff --git a/Base/Geometry/imstkMesh.h b/Base/Geometry/imstkMesh.h index 43e7011213bae18540725ef7ffa08188999b9677..378361cb72c09de9c6249670af82d2d45d66058a 100644 --- a/Base/Geometry/imstkMesh.h +++ b/Base/Geometry/imstkMesh.h @@ -31,15 +31,27 @@ public: ~Mesh() = default; + // Accessors const std::vector<Vec3d>& getInitialVertexPositions() const; void setInitialVertexPositions(const std::vector<Vec3d>& vertices); + const imstk::Vec3d& getInitialVertexPosition(const int vertNum) const; + const std::vector<Vec3d>& getVertexPositions() const; void setVertexPositions(const std::vector<Vec3d>& vertices); + const imstk::Vec3d& getVertexPosition(const int vertNum) const; + void setVertexPosition(const int vertNum, const imstk::Vec3d& pos); + const std::vector<Vec3d>& getVertexDisplacements() const; void setVertexDisplacements(const std::vector<Vec3d>& diff); + const imstk::Vec3d& getVertexDisplacement(const int vertNum) const; + + int getNumVertices() const; + + void computeBoundingBox(imstk::Vec3d& min, imstk::Vec3d& max, const double percent = 0.0) const; + protected: Mesh(GeometryType type) : Geometry(type, WORLD_ORIGIN, Quatd()) {} diff --git a/Base/Geometry/imstkPlane.cpp b/Base/Geometry/imstkPlane.cpp index 7093d14ca310bc82e5a853be0f0eeb2847ddb2cf..1f1625a72bee181f7711376b5b33c8fc6359a8ae 100644 --- a/Base/Geometry/imstkPlane.cpp +++ b/Base/Geometry/imstkPlane.cpp @@ -45,4 +45,10 @@ Plane::setWidth(const double& width) { m_width = width; } + +double +Plane::getVolume() const +{ + return 0.0; +} } diff --git a/Base/Geometry/imstkPlane.h b/Base/Geometry/imstkPlane.h index 0acb5c941acf6e04a72fd16f351f01e7c55c4dab..e0395e93eaad5e6674bec8b9b36991c54a66003f 100644 --- a/Base/Geometry/imstkPlane.h +++ b/Base/Geometry/imstkPlane.h @@ -46,6 +46,7 @@ public: const double& getWidth() const; void setWidth(const double& width); + double getVolume() const; protected: double m_width; diff --git a/Base/Geometry/imstkSphere.cpp b/Base/Geometry/imstkSphere.cpp index edfa76ec0ff596941ce53e2af47166b74c8c29c6..86780f482db6bd670eef1b75c60db8baccaa109e 100644 --- a/Base/Geometry/imstkSphere.cpp +++ b/Base/Geometry/imstkSphere.cpp @@ -33,4 +33,11 @@ Sphere::setRadius(const double& radius) { m_radius = radius; } + +double +Sphere::getVolume() const +{ + return 0.75*imstk::PI*m_radius*m_radius*m_radius; +} + } diff --git a/Base/Geometry/imstkSphere.h b/Base/Geometry/imstkSphere.h index d07c9a3b4335445cca15268ebed18db47238729d..96d5c7bfafbae12cace4a2fd7a7722bc58d4f189 100644 --- a/Base/Geometry/imstkSphere.h +++ b/Base/Geometry/imstkSphere.h @@ -42,6 +42,7 @@ public: const double& getRadius() const; void setRadius(const double& radius); + double getVolume() const; protected: double m_radius; diff --git a/Base/Geometry/imstkSurfaceMesh.cpp b/Base/Geometry/imstkSurfaceMesh.cpp index c309a2588018e5502fd4c0f1bbac91dd1fff3024..15e765457c9295a40f32bb46129feacfdbfd6171 100644 --- a/Base/Geometry/imstkSurfaceMesh.cpp +++ b/Base/Geometry/imstkSurfaceMesh.cpp @@ -237,4 +237,27 @@ SurfaceMesh::getVertexTangent(size_t i) const { return m_vertexTangents.at(i); } + +const imstk::Vec3d & SurfaceMesh::getVertexInitialPosition(size_t i) const +{ + return m_initialVertexPositions.at(i); +} + +const imstk::Vec3d & SurfaceMesh::getVertexPosition(size_t i) const +{ + return m_vertexPositions.at(i); +} + +double +SurfaceMesh::getVolume() const +{ + // TODO + // 1. Check for water tightness + // 2. Compute volume based on signed distance + + LOG(WARNING) << "Not supported yet, returns 0.0!\n"; + + return 0.0; +} + } diff --git a/Base/Geometry/imstkSurfaceMesh.h b/Base/Geometry/imstkSurfaceMesh.h index 2cfab16c0ec833d53975d46db8d9cdfd2f445031..abe286dc5f1d3f7ed57bbae9de37968bd4556190 100644 --- a/Base/Geometry/imstkSurfaceMesh.h +++ b/Base/Geometry/imstkSurfaceMesh.h @@ -62,6 +62,10 @@ public: const std::vector<Vec4d>& getVertexTangents() const; const Vec4d & getVertexTangent(size_t i) const; + const Vec3d & getVertexInitialPosition(size_t i) const; + const Vec3d & getVertexPosition(size_t i) const; + + double getVolume() const; protected: std::vector<TriangleArray> m_triangleVertices; diff --git a/Base/Geometry/imstkTetraTriangleMap.cpp b/Base/Geometry/imstkTetraTriangleMap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dd4068e8aad9a34c4d162b42424cb27138996e4a --- /dev/null +++ b/Base/Geometry/imstkTetraTriangleMap.cpp @@ -0,0 +1,182 @@ +/*========================================================================= + + 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 "imstkTetraTriangleMap.h" + +namespace imstk +{ + +void +TetraTriangleMap::computeMap() +{ + if (!m_master || !m_slave) + { + LOG(WARNING) << "TetraTriangle map is being applied without valid geometries\n"; + return; + } + + // Proceed to generate the map + auto tetMesh = std::dynamic_pointer_cast<imstk::TetrahedralMesh> (m_master); + auto triMesh = std::dynamic_pointer_cast<imstk::SurfaceMesh> (m_slave); + + weightsArray weights; + int numSurfaceVertices = triMesh->getNumVertices(); + int numTetrahedra = tetMesh->getNumTetrahedra(); + + for (int i = 0; i < numSurfaceVertices; ++i) + { + imstk::Vec3d surfVertPos = triMesh->getVertexInitialPosition(i); + + // find the enclosing element + int closestEle = findEclosingTetrahedra(tetMesh, surfVertPos); + + // if not inside of any element, + // find the tetrahedra whose centroid is the closest + if (closestEle < 0) + { + closestEle = findClosestTetrahedra(tetMesh, surfVertPos); + } + + // compute the weights + tetMesh->computeBarycentricWeights(closestEle, surfVertPos, weights); + + m_enclosingTetra.push_back(closestEle);// store nearest tetrahedra + m_weights.push_back(weights);// store weights + } +} + +int +TetraTriangleMap::findClosestTetrahedra(const std::shared_ptr<imstk::TetrahedralMesh> tetraMesh, const imstk::Vec3d& p) +{ + // search + double closestDistance = std::numeric_limits<double>::max(); + int closestTetrahedra = -1; + for (int t = 0; t < tetraMesh->getNumTetrahedra(); ++t) + { + imstk::Vec3d center(0, 0, 0); + auto vert = tetraMesh->getTetrahedronVertices(t); + for (int i = 0; i < 4; ++i) + { + center += tetraMesh->getInitialVertexPosition(vert[i]); + } + + double dist = (p - center).norm(); + if (dist < closestDistance) + { + closestDistance = dist; + closestTetrahedra = t; + } + } + + return closestTetrahedra; +} + +int +TetraTriangleMap::findEclosingTetrahedra(const std::shared_ptr<imstk::TetrahedralMesh> tetraMesh, const imstk::Vec3d& p) +{ + imstk::Vec3d boundingBoxMin; + imstk::Vec3d boundingBoxMax; + std::vector<int> probables; + + // Eliminate the improbables based in bounding box test + for (int t = 0; t < tetraMesh->getNumTetrahedra(); ++t) + { + tetraMesh->computeTetrahedraBoundingBox(boundingBoxMin, boundingBoxMax, t); + + if ((p[0] >= boundingBoxMin[0] && p[0] <= boundingBoxMax[0]) && + (p[1] >= boundingBoxMin[1] && p[1] <= boundingBoxMax[1]) && + (p[2] >= boundingBoxMin[2] && p[2] <= boundingBoxMax[2])) + { + probables.push_back(t); + } + } + + // Check which probable tetrahedra the point belongs to + int elclosingTetra = -1; + weightsArray weights; + for (auto it = probables.begin(); it != probables.end(); ++it) + { + tetraMesh->computeBarycentricWeights(*it, p, weights); + + if ((weights[0] >= 0) && (weights[1] >= 0) && (weights[2] >= 0) && (weights[3] >= 0)) + { + elclosingTetra = *it; + break; + } + } + return elclosingTetra; +} + +void +TetraTriangleMap::setMaster(std::shared_ptr<Geometry> master) +{ + if (master->getType() == imstk::GeometryType::TetrahedralMesh) + { + m_master = master; + } + else + { + LOG(WARNING) << "The geometry provided is not of tetrahedral type\n"; + } +} + +void +TetraTriangleMap::setSlave(std::shared_ptr<Geometry> slave) +{ + if (slave->getType() == imstk::GeometryType::SurfaceMesh) + { + m_slave = slave; + } + else + { + LOG(WARNING) << "The geometry provided is not of surface triangular type\n"; + } + +} + +void +TetraTriangleMap::applyMap() +{ + if (m_isActive) + { + if (!m_master || !m_slave) + { + LOG(WARNING) << "TetraTriangle map is not completely defined!\n"; + return; + } + + auto tetMesh = std::dynamic_pointer_cast<imstk::TetrahedralMesh> (m_master); + auto triMesh = std::dynamic_pointer_cast<imstk::SurfaceMesh> (m_slave); + + imstk::Vec3d newPos; + for (int v = 0; v < triMesh->getNumVertices(); ++v) + { + newPos.setZero(); + auto tetVerts = tetMesh->getTetrahedronVertices(m_enclosingTetra[v]); + for (int i = 0; i < 4; ++i) + { + newPos += tetMesh->getInitialVertexPosition(tetVerts[i]) * m_weights.at(v)[i]; + } + triMesh->setVertexPosition(v, newPos); + } + } +} +} \ No newline at end of file diff --git a/Base/Geometry/imstkTetraTriangleMap.h b/Base/Geometry/imstkTetraTriangleMap.h new file mode 100644 index 0000000000000000000000000000000000000000..8d1e1203fab7f959666e415807233cc0acc00d0b --- /dev/null +++ b/Base/Geometry/imstkTetraTriangleMap.h @@ -0,0 +1,89 @@ +/*========================================================================= + + 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 imstkTetraTriangleMap_h +#define imstkTetraTriangleMap_h + +#include <limits> + +#include "imstkGeometryMap.h" +#include "imstkTetrahedralMesh.h" +#include "imstkSurfaceMesh.h" + +namespace imstk { + +/// +/// \class TetraTriangleMap +/// +/// \brief Computes and applies the triangle-tetrahedra map. The master mesh is the +/// tetrahedral mesh and the slave is the surface triangular mesh. +/// +class TetraTriangleMap : public GeometryMap +{ + using weightsArray = std::array<double, 4>; + +public: + + ~TetraTriangleMap() = default; + + TetraTriangleMap() : GeometryMap(GeometryMapType::TetraTriangle){} + + /// + /// \brief Apply (if active) the tetra-triangle mesh map + /// + void applyMap(); + + /// + /// \brief Compute the tetra-triangle mesh map + /// + void computeMap(); + + // Generic utility functions + + /// + /// \brief Find the closest tetrahedra based on the distance to their centroids for a given point in 3D space + /// + static int findClosestTetrahedra(const std::shared_ptr<imstk::TetrahedralMesh> tetraMesh, const imstk::Vec3d& p); + + /// + /// \brief Find the tetrahedra that encloses a given point in 3D space + /// + static int findEclosingTetrahedra(const std::shared_ptr<imstk::TetrahedralMesh> tetraMesh, const imstk::Vec3d& p); + + // Accessors + + /// + /// \brief Set the geometry that dictates the map + /// + void setMaster(std::shared_ptr<Geometry> master) override; + + /// + /// \brief Set the geometry that follows the master + /// + void setSlave(std::shared_ptr<Geometry> slave) override; + +protected: + std::vector<weightsArray> m_weights; ///> weights + std::vector<int> m_enclosingTetra; ///> Enclosing tetrahedra to interpolate the weights upon +}; +} + +#endif // imstkTetraTriangleMap_h diff --git a/Base/Geometry/imstkTetrahedralMesh.cpp b/Base/Geometry/imstkTetrahedralMesh.cpp index eee4dca4f9796a252afc5758f7d6d052e607d27f..bed460a41609770d15d623dc640ba473670aa36f 100644 --- a/Base/Geometry/imstkTetrahedralMesh.cpp +++ b/Base/Geometry/imstkTetrahedralMesh.cpp @@ -28,9 +28,103 @@ TetrahedralMesh::getTetrahedronVertices() const return m_tetrahedronVertices; } +const imstk::TetrahedralMesh::TetraArray& TetrahedralMesh::getTetrahedronVertices(const int tetraNum) const +{ + return m_tetrahedronVertices.at(tetraNum); +} + void TetrahedralMesh::setTetrahedronVertices(const std::vector<TetraArray>& tetrahedrons) { m_tetrahedronVertices = tetrahedrons; } + +void +TetrahedralMesh::computeBarycentricWeights(const int closestEle, const imstk::Vec3d& p, std::array<double, 4> weights) const +{ + TetraArray vertIndices = getTetrahedronVertices(closestEle); + imstk::Vec3d v[4]; + double dets[4]; + double det; + + for (int i = 0; i < 4; i++) + { + v[i] = getVertexPosition(vertIndices[i]); + } + + Eigen::Matrix4d A; + A << v[0][0], v[0][1], v[0][2], 1, + v[1][0], v[1][1], v[1][2], 1, + v[2][0], v[2][1], v[2][2], 1, + v[3][0], v[3][1], v[3][2], 1; + + det = A.determinant(); + + for (int i = 0; i < 4; i++) + { + Eigen::Matrix4d B = A; + B(i, 0) = p[0]; + B(i, 1) = p[1]; + B(i, 2) = p[2]; + weights[i] = B.determinant() / det; + } +} + +void +TetrahedralMesh::computeTetrahedraBoundingBox(imstk::Vec3d& min, imstk::Vec3d& max, const int tetNum) const +{ + auto v1 = getVertexPosition(m_tetrahedronVertices.at(tetNum)[0]); + auto v2 = getVertexPosition(m_tetrahedronVertices.at(tetNum)[1]); + auto v3 = getVertexPosition(m_tetrahedronVertices.at(tetNum)[2]); + auto v4 = getVertexPosition(m_tetrahedronVertices.at(tetNum)[3]); + + std::array<double, 4> arrayx = { v1[0], v2[0], v3[0], v4[0] }; + std::array<double, 4> arrayy = { v1[1], v2[1], v3[1], v4[1] }; + std::array<double, 4> arrayz = { v1[2], v2[2], v3[2], v4[2] }; + + min[0] = *std::min_element(arrayx.begin(), arrayx.end()); + min[1] = *std::min_element(arrayy.begin(), arrayy.end()); + min[2] = *std::min_element(arrayz.begin(), arrayz.end()); + + max[0] = *std::max_element(arrayx.begin(), arrayx.end()); + max[1] = *std::max_element(arrayy.begin(), arrayy.end()); + max[2] = *std::max_element(arrayz.begin(), arrayz.end()); +} + +double +TetrahedralMesh::getVolume() const +{ + imstk::Vec3d v[4]; + Eigen::Matrix4d A; + double volume = 0.0; + for (auto it = m_tetrahedronVertices.begin(); it != m_tetrahedronVertices.end(); ++it) + { + for (int i = 0; i < 4; i++) + { + v[i] = getVertexPosition((*it)[i]); + } + + A << v[0][0], v[0][1], v[0][2], 1, + v[1][0], v[1][1], v[1][2], 1, + v[2][0], v[2][1], v[2][2], 1, + v[3][0], v[3][1], v[3][2], 1; + + double det = A.determinant(); + if (det < 0) + { + LOG(WARNING) << "Tetrahedon is inverted, has negative volume!\n"; + } + + volume += std::abs(det)/6; + } + + return volume; +} + +int +TetrahedralMesh::getNumTetrahedra() const +{ + return m_tetrahedronVertices.size(); +} + } diff --git a/Base/Geometry/imstkTetrahedralMesh.h b/Base/Geometry/imstkTetrahedralMesh.h index 84f3ad4981e3bab03c2abfdb44f07b9a5436adab..d548e9d5ff0600d684607cb68e23047896e7657e 100644 --- a/Base/Geometry/imstkTetrahedralMesh.h +++ b/Base/Geometry/imstkTetrahedralMesh.h @@ -39,8 +39,32 @@ public: // Accessors const std::vector<TetraArray>& getTetrahedronVertices() const; - void setTetrahedronVertices( - const std::vector<TetraArray>& tetrahedrons); + void setTetrahedronVertices(const std::vector<TetraArray>& tetrahedrons); + + /// + /// \brief Returns the number of tetrahedra + /// + int getNumTetrahedra() const; + + /// + /// \brief compute the barycentric weights of a given point in 3D space for a given the tetrahedra + /// + void computeBarycentricWeights(const int closestEle, const imstk::Vec3d& p, std::array<double, 4> weights) const; + + /// + /// \brief get the indices vertices of a given tetrahedra in an array + /// + const TetraArray& getTetrahedronVertices(const int tetraNum) const; + + /// + /// \brief Compute the bounding box of a given tetrahedra + /// + void computeTetrahedraBoundingBox(imstk::Vec3d& min, imstk::Vec3d& max, const int tetNum) const; + + /// + /// \brief Compute and return the volume of the tetrahedral mesh + /// + double getVolume() const; protected: diff --git a/Examples/Sandbox/main.cpp b/Examples/Sandbox/main.cpp index 9e979ea24f227bb03d3e042694621a5c92607e16..d33a5b07a11a8854904a4f021bec5856c1b24760 100644 --- a/Examples/Sandbox/main.cpp +++ b/Examples/Sandbox/main.cpp @@ -30,7 +30,7 @@ int main() testViewer(); //testAnalyticalGeometry(); //testScenesManagement(); - //testGeometryMaps(); + //testIsometricMaps(); return 0; } @@ -178,7 +178,15 @@ void testScenesManagement() while (sdk->getStatus() != imstk::SimulationStatus::INACTIVE) {} } -void testGeometryMaps() +void testTetraTriangleMap() +{ + // SDK and Scene + auto sdk = std::make_shared<imstk::SimulationManager>(); + auto geometryMapTest = sdk->createNewScene("geometryMapTest"); + geometryMapTest->setLoopDelay(1000); +} + +void testIsometricMaps() { // SDK and Scene auto sdk = std::make_shared<imstk::SimulationManager>();