diff --git a/Base/Collision/CMakeLists.txt b/Base/Collision/CMakeLists.txt index 2d08c9227750aef01bcf228f1673161287a28ae2..5322eb1b193f659ba3f65c0168bb259e7a952272 100644 --- a/Base/Collision/CMakeLists.txt +++ b/Base/Collision/CMakeLists.txt @@ -12,6 +12,7 @@ imstk_add_library( Collision #----------------------------------------------------------------------------- # Testing #----------------------------------------------------------------------------- -if( iMSTK_BUILD_TESTING ) - add_subdirectory( Testing ) +if( BUILD_TESTING ) + include(imstkAddTest) + imstk_add_test( Collision ) endif() diff --git a/Base/Collision/CollisionData/imstkCollisionData.h b/Base/Collision/CollisionData/imstkCollisionData.h index 16a784b74d4d05dcc53bb798bced5c466efdb1e7..bc93c0c08b27cf69cf4f0af617e6ee381802548c 100644 --- a/Base/Collision/CollisionData/imstkCollisionData.h +++ b/Base/Collision/CollisionData/imstkCollisionData.h @@ -22,6 +22,8 @@ #ifndef imstkCollisionData_h #define imstkCollisionData_h +#include <array> + // imstk #include "imstkMath.h" @@ -109,6 +111,25 @@ struct EdgeEdgeCollisionData } }; +/// +/// \struct PointTetrahedronCollisionData +/// +/// \brief Point-tetrahedron collision data +/// +struct PointTetrahedronCollisionData +{ + enum CollisionType { + aPenetratingA = 0, // A self-penetration + aPenetratingB = 1, // vertex is from mesh A, tetrahedron is from mesh B + bPenetratingA = 2, // vertex is from mesh B, tetrahedron is from mesh A + bPenetratingB = 3 // B self-penetration + } collisionType; + size_t vertexId; + size_t tetreahedronId; + using WeightsArray = std::array<double, 4>; + WeightsArray BarycentricCoordinates; +}; + /// /// \struct CollisionData /// @@ -124,6 +145,8 @@ public: VTColData.clear(); TVColData.clear(); EEColData.clear(); + MAColData.clear(); + PTColData.clear(); } std::vector<PositionDirectionCollisionData> PDColData; ///< Position Direction collision data @@ -131,6 +154,7 @@ public: std::vector<TriangleVertexCollisionData> TVColData; ///< Triangle Vertex collision data std::vector<EdgeEdgeCollisionData> EEColData; ///< Edge Edge collision data std::vector<MeshToAnalyticalCollisionData> MAColData; ///< Mesh to analytical collision data + std::vector<PointTetrahedronCollisionData> PTColData; ///< Point Tetrahedron collision data }; } diff --git a/Base/Collision/CollisionDetection/DataStructures/imstkSpatialHashTable.h b/Base/Collision/CollisionDetection/DataStructures/imstkSpatialHashTable.h index 14142d92d1b500e5b37ada2bceaf59a40bf9a139..a8bf1e6dfa1b76d1816e064d811cbf98d7c0008f 100644 --- a/Base/Collision/CollisionDetection/DataStructures/imstkSpatialHashTable.h +++ b/Base/Collision/CollisionDetection/DataStructures/imstkSpatialHashTable.h @@ -39,13 +39,13 @@ public: /// \brief Protected constructor /// \param x,y,z Dimensions for each cell /// - virtual void setCellSize(double x, double y, double z); + virtual void setCellSize(double x, double y, double z) = 0; protected: /// /// \brief Rehash the hash table /// - virtual void rehash(); + virtual void rehash() = 0; /// /// \brief Protected constructor diff --git a/Base/Collision/CollisionDetection/DataStructures/imstkSpatialHashTableSeparateChaining.cpp b/Base/Collision/CollisionDetection/DataStructures/imstkSpatialHashTableSeparateChaining.cpp index 70aa965ead796396581135f177a9b3e006301400..0db7450c69853571125a5042a918160366c6668d 100644 --- a/Base/Collision/CollisionDetection/DataStructures/imstkSpatialHashTableSeparateChaining.cpp +++ b/Base/Collision/CollisionDetection/DataStructures/imstkSpatialHashTableSeparateChaining.cpp @@ -109,10 +109,6 @@ SpatialHashTableSeparateChaining::getPointsInAABB(const Vec3d& corner1, const Ve } } - //there is little need to waste time on this reallocation, - //as this is a temporary return array - //points.shrink_to_fit(); - return points; } diff --git a/Base/Collision/CollisionDetection/DataStructures/imstkSpatialHashTableSeparateChaining.h b/Base/Collision/CollisionDetection/DataStructures/imstkSpatialHashTableSeparateChaining.h index 49119c92cb26563a184a80df32983f74326374be..f627e56cfa5a57316a9d14245d6e58cfb27191b4 100644 --- a/Base/Collision/CollisionDetection/DataStructures/imstkSpatialHashTableSeparateChaining.h +++ b/Base/Collision/CollisionDetection/DataStructures/imstkSpatialHashTableSeparateChaining.h @@ -59,12 +59,12 @@ template<> struct equal_to<imstk::PointEntry> { size_t operator()(const imstk::PointEntry& point1, const imstk::PointEntry& point2) const { - if (point1.point != point2.point) + if (point1.ID != point2.ID) { return false; } - if (point1.ID != point2.ID) + if (point1.point != point2.point) { return false; } @@ -125,19 +125,13 @@ public: /// \brief Protected constructor /// \param x,y,z Dimensions for each cell /// - virtual void setCellSize(double x, double y, double z); + virtual void setCellSize(double x, double y, double z) override; protected: /// /// \brief Rehash the hash table /// - virtual void rehash(); - - /// - /// \brief Hash function - /// \param point A point - /// - inline unsigned int generateHash(Vec3d point); + virtual void rehash() override; float m_loadFactorMax = 10.0f; diff --git a/Base/Collision/CollisionDetection/imstkTetraToTetraCD.cpp b/Base/Collision/CollisionDetection/imstkTetraToTetraCD.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b64343db25f6cfc6a71998913af2a5e13e318d08 --- /dev/null +++ b/Base/Collision/CollisionDetection/imstkTetraToTetraCD.cpp @@ -0,0 +1,117 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version B.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-B.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 "imstkTetraToTetraCD.h" + +#include "imstkCollisionData.h" +#include "imstkMath.h" + +#include <g3log/g3log.hpp> + +namespace imstk { + +TetraToTetraCD::TetraToTetraCD(std::shared_ptr<TetrahedralMesh> meshA, + std::shared_ptr<TetrahedralMesh> meshB, + CollisionData& colData) : + CollisionDetection(CollisionDetection::Type::MeshToMesh, colData), //is TetrahedralMeshToTetrahedralMesh type needed? + m_meshA(meshA), + m_meshB(meshB) +{ +} + +void +TetraToTetraCD::findCollisionsForMeshWithinHashTable(const std::shared_ptr<TetrahedralMesh> mesh, size_t idOffset) +{ + Vec3d min, max; //bounding box of a tetrahedron + Vec3d vPos; + const auto eps = MACHINE_PRECISION; + const double eps2 = 1e-10; + + //tetrahedron belonging part of penetration type does not change + PointTetrahedronCollisionData::CollisionType cType + = static_cast<PointTetrahedronCollisionData::CollisionType>(idOffset > 0); + + for (size_t tId = 0; tId < mesh->getNumTetrahedra(); ++tId) //TODO: parallelize! + { + TetrahedralMesh::TetraArray vInd = mesh->getTetrahedronVertices(tId); + for (int i = 0; i < 4; i++) //if idOffset!=0 ? + { + vInd[i] += idOffset; + } + mesh->computeTetrahedronBoundingBox(tId, min, max); + std::vector<size_t> collP = m_hashTable.getPointsInAABB(min, max); + assert(collP.size() >= 4); + if (collP.size() > 4) + { + for (size_t vId : collP) + { + //vertex does not belong to this tetrahedron + if (vId != vInd[0] && + vId != vInd[1] && + vId != vInd[2] && + vId != vInd[3]) + { + //this determines vertex belonging part of the penetration type + //and gets vertex position + if (vId < m_meshA->getNumVertices()) + { + vPos = m_meshA->getVertexPosition(vId); + cType = static_cast<PointTetrahedronCollisionData::CollisionType>((cType & 1) + 0); + } + else + { + vId -= m_meshA->getNumVertices(); + vPos = m_meshB->getVertexPosition(vId); + cType = static_cast<PointTetrahedronCollisionData::CollisionType>((cType & 1) + 2); + } + + TetrahedralMesh::WeightsArray bCoord; //barycentric coordinates of the vertex in tetrahedron + mesh->computeBarycentricWeights(tId, vPos, bCoord); + if (bCoord[0] >= -eps && + bCoord[1] >= -eps && + bCoord[2] >= -eps && + bCoord[3] >= -eps) + { + auto coordSum = bCoord[0] + bCoord[1] + bCoord[2] + bCoord[3]; + assert(coordSum <= 1 + eps2 && coordSum >= 1 - eps2); + + PointTetrahedronCollisionData ptColl = { cType, vId, tId, bCoord }; + m_colData.PTColData.push_back(ptColl); + } + } //if not this tetrahedron + } //for vertices + } + } //for tetrahedra +} + +void +TetraToTetraCD::computeCollisionData() +{ + m_hashTable.clear(); + m_hashTable.insertPoints(m_meshA->getVertexPositions()); + m_hashTable.insertPoints(m_meshB->getVertexPositions()); + + m_colData.clearAll(); + this->findCollisionsForMeshWithinHashTable(m_meshA, 0); + this->findCollisionsForMeshWithinHashTable(m_meshB, m_meshA->getNumVertices()); +} + +} diff --git a/Base/Collision/CollisionDetection/imstkTetraToTetraCD.h b/Base/Collision/CollisionDetection/imstkTetraToTetraCD.h new file mode 100644 index 0000000000000000000000000000000000000000..754d9f65e16cbfaa9ba177f66b6d991d8617de0f --- /dev/null +++ b/Base/Collision/CollisionDetection/imstkTetraToTetraCD.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 imstkTetrahedralMeshCD_h +#define imstkTetrahedralMeshCD_h + +// std library +#include <memory> + +// imstk +#include "imstkCollisionDetection.h" +#include "imstkTetrahedralMesh.h" +#include "DataStructures/imstkSpatialHashTableSeparateChaining.h" +#include "DeformModel.h" + +namespace imstk +{ + +class CollisionData; + +/// +/// \class TetraToTetraCD +/// +/// \brief Base class for mesh-to-mesh collision detection +/// +class TetraToTetraCD : public CollisionDetection +{ +public: + + /// + /// \brief Constructor + /// + TetraToTetraCD(std::shared_ptr<TetrahedralMesh> meshA, + std::shared_ptr<TetrahedralMesh> meshB, + CollisionData& colData); + + /// + /// \brief Destructor + /// + ~TetraToTetraCD() = default; + + /// + /// \brief Detect collision and compute collision data + /// + void computeCollisionData() override; + +private: + + /// + /// \brief Processes tetrahedrons of either mesh A or B. + /// + /// This method goes through tetrahedrons of the supplied mesh (A or B), + /// and examines vertices currently in the hash table. + /// It first does rough intersection check using AABB, + /// and then finer check using barycentric coordinates. + /// Collisions are added to m_colData + /// Self collisions and mutual collisions between A and B are supported. + /// + /// \param mesh must be either m_meshA or m_meshB + /// \param idOffset must be 0 for A, and A.getNumVertices() for B + /// + void findCollisionsForMeshWithinHashTable(const std::shared_ptr<TetrahedralMesh> mesh, size_t idOffset); + + std::shared_ptr<TetrahedralMesh> m_meshA; ///> Mesh A + std::shared_ptr<TetrahedralMesh> m_meshB; ///> Mesh B + SpatialHashTableSeparateChaining m_hashTable; ///> Spatial hash table +}; + +} + +#endif // ifndef imstkTetrahedralMeshCD_h diff --git a/Base/Collision/Testing/imstkTetraToTetraCDTest.cpp b/Base/Collision/Testing/imstkTetraToTetraCDTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1e36143c4aea765897b34b8084d9a130a1a6a630 --- /dev/null +++ b/Base/Collision/Testing/imstkTetraToTetraCDTest.cpp @@ -0,0 +1,143 @@ +#include "gtest/gtest.h" +#include "gmock/gmock.h" + +#include <memory> + +#include "imstkCollisionData.h" +#include "imstkIsometricMap.h" +#include "imstkMeshIO.h" +#include "imstkTetraToTetraCD.h" + +using namespace imstk; + +class imstkTetraToTetraCDTest : public ::testing::Test +{ +protected: + TetraToTetraCD *m_CD; +}; + +std::shared_ptr<TetrahedralMesh> loadMesh(std::string externalDataSuffix) +{ + std::string file = iMSTK_DATA_ROOT + externalDataSuffix; + std::shared_ptr<TetrahedralMesh> volMesh + = std::static_pointer_cast<TetrahedralMesh>(imstk::MeshIO::read(file)); + if (!volMesh) + { + LOG(FATAL) << "Failed to read a volumetric mesh file : " << file; + } + return volMesh; +} + +std::shared_ptr<TetrahedralMesh> duplicate(std::shared_ptr<TetrahedralMesh> mesh) +{ + return std::make_shared<TetrahedralMesh>(*mesh.get()); +} + +TEST_F(imstkTetraToTetraCDTest, NoSelfIntersection) +{ + std::shared_ptr<TetrahedralMesh> a = loadMesh("/asianDragon/asianDragon.veg"); + auto b = std::make_shared<TetrahedralMesh>(TetrahedralMesh()); //empty mesh + CollisionData cd; + + m_CD = new TetraToTetraCD(a, b, cd); + m_CD->computeCollisionData(); + EXPECT_EQ(cd.PTColData.size(), 0); + + m_CD = new TetraToTetraCD(b, a, cd); + m_CD->computeCollisionData(); + EXPECT_EQ(cd.PTColData.size(), 0); +} + +TEST_F(imstkTetraToTetraCDTest, IntersectionThenNoIntersection1T) +{ + std::shared_ptr<TetrahedralMesh> a = loadMesh("/oneTet/oneTet.veg"); + auto b = duplicate(a); + + b->translateVertices(imstk::Vec3d(0.0, 1.0, 2.5)); + + CollisionData cd; + m_CD = new TetraToTetraCD(a, b, cd); + m_CD->computeCollisionData(); + EXPECT_EQ(cd.PTColData.size(), 1); + EXPECT_EQ(cd.PTColData[0].collisionType, PointTetrahedronCollisionData::bPenetratingA); + EXPECT_EQ(cd.PTColData[0].vertexId, 0); + EXPECT_EQ(cd.PTColData[0].tetreahedronId, 0); + + m_CD = new TetraToTetraCD(b, a, cd); + m_CD->computeCollisionData(); + EXPECT_EQ(cd.PTColData.size(), 1); + EXPECT_EQ(cd.PTColData[0].collisionType, PointTetrahedronCollisionData::aPenetratingB); + EXPECT_EQ(cd.PTColData[0].vertexId, 0); + EXPECT_EQ(cd.PTColData[0].tetreahedronId, 0); + + //now translate b more so there is no intersection + b->translateVertices(imstk::Vec3d(0.0, 2.0, 0.0)); + + m_CD = new TetraToTetraCD(b, a, cd); + m_CD->computeCollisionData(); + EXPECT_EQ(cd.PTColData.size(), 0); + + m_CD = new TetraToTetraCD(a, b, cd); + m_CD->computeCollisionData(); + EXPECT_EQ(cd.PTColData.size(), 0); +} + +TEST_F(imstkTetraToTetraCDTest, IntersectionThenNoIntersectionHuman) +{ + std::shared_ptr<TetrahedralMesh> a = loadMesh("/human/human.veg"); + auto b = duplicate(a); + + b->translateVertices(imstk::Vec3d(16.0, 0.0, 1.0)); + CollisionData cd; + + m_CD = new TetraToTetraCD(a, b, cd); + m_CD->computeCollisionData(); + EXPECT_EQ(cd.PTColData.size(), 4); + + m_CD = new TetraToTetraCD(b, a, cd); + m_CD->computeCollisionData(); + EXPECT_EQ(cd.PTColData.size(), 4); + + //this additional translation produces a different intersection + b->translateVertices(imstk::Vec3d(0.0, 0.0, 0.5)); + + m_CD = new TetraToTetraCD(a, b, cd); + m_CD->computeCollisionData(); + EXPECT_EQ(cd.PTColData.size(), 1); + EXPECT_EQ(cd.PTColData[0].collisionType, PointTetrahedronCollisionData::aPenetratingB); + EXPECT_EQ(cd.PTColData[0].vertexId, 81); + EXPECT_EQ(cd.PTColData[0].tetreahedronId, 367); + + m_CD = new TetraToTetraCD(b, a, cd); + m_CD->computeCollisionData(); + EXPECT_EQ(cd.PTColData.size(), 1); + EXPECT_EQ(cd.PTColData[0].collisionType, PointTetrahedronCollisionData::bPenetratingA); + EXPECT_EQ(cd.PTColData[0].vertexId, 81); + EXPECT_EQ(cd.PTColData[0].tetreahedronId, 367); + + //now translate b more so there is no intersection + b->translateVertices(imstk::Vec3d(0.0, 0.0, 1.0)); + m_CD = new TetraToTetraCD(a, b, cd); + m_CD->computeCollisionData(); + EXPECT_EQ(cd.PTColData.size(), 0); +} + +TEST_F(imstkTetraToTetraCDTest, IntersectionOfDifferentMeshes) +{ + std::shared_ptr<TetrahedralMesh> a = loadMesh("/asianDragon/asianDragon.veg"); + std::shared_ptr<TetrahedralMesh> b = loadMesh("/human/human.veg"); + + CollisionData cd; + m_CD = new TetraToTetraCD(a, b, cd); + m_CD->computeCollisionData(); + EXPECT_EQ(cd.PTColData.size(), 595); +} + +int imstkTetraToTetraCDTest(int argc, char* argv[]) +{ + // Init Google Test & Mock + ::testing::InitGoogleTest(&argc, argv); + + // Run tests with gtest + return RUN_ALL_TESTS(); +} diff --git a/Base/Geometry/Map/imstkOneToOneMap.cpp b/Base/Geometry/Map/imstkOneToOneMap.cpp index c0ebc6182c7895f9c69c3b51bf6c36cb04810545..e25367ae150ab40840e53e04f9ac544afc263b25 100644 --- a/Base/Geometry/Map/imstkOneToOneMap.cpp +++ b/Base/Geometry/Map/imstkOneToOneMap.cpp @@ -34,7 +34,7 @@ OneToOneMap::compute() } // returns the first matching vertex - auto findMatchingVertex = [](std::shared_ptr<Mesh> masterMesh, const Vec3d& p) -> int + auto findMatchingVertex = [](std::shared_ptr<Mesh> masterMesh, const Vec3d& p) -> size_t { for (size_t nodeId = 0; nodeId < masterMesh->getNumVertices(); ++nodeId) { @@ -53,7 +53,7 @@ OneToOneMap::compute() for (size_t nodeId = 0; nodeId < meshSlave->getNumVertices(); ++nodeId) { // Find the enclosing or closest tetrahedron - int matchingNodeId = findMatchingVertex(meshMaster, meshSlave->getVertexPosition(nodeId)); + size_t matchingNodeId = findMatchingVertex(meshMaster, meshSlave->getVertexPosition(nodeId)); if (matchingNodeId < 0) { diff --git a/Base/Geometry/Map/imstkTetraTriangleMap.cpp b/Base/Geometry/Map/imstkTetraTriangleMap.cpp index 8b935a97156220ee9df55f067dc06cb6d43fa004..ff664631ecdb46c9dddd51f9748f22ff683a5141 100644 --- a/Base/Geometry/Map/imstkTetraTriangleMap.cpp +++ b/Base/Geometry/Map/imstkTetraTriangleMap.cpp @@ -160,7 +160,7 @@ TetraTriangleMap::findClosestTetrahedron(std::shared_ptr<TetrahedralMesh> tetraM const Vec3d& pos) { double closestDistance = MAX_D; - int closestTetrahedron = -1; + size_t closestTetrahedron = -1; for (size_t tetId = 0; tetId < tetraMesh->getNumTetrahedra(); ++tetId) { Vec3d center(0, 0, 0); diff --git a/Base/Geometry/Mesh/imstkMesh.cpp b/Base/Geometry/Mesh/imstkMesh.cpp index 67b098d4b23de42612ad4ff3741232d322036868..2eee5ac12a7d40bf2c2b1aacc9e263fd0699cd6e 100644 --- a/Base/Geometry/Mesh/imstkMesh.cpp +++ b/Base/Geometry/Mesh/imstkMesh.cpp @@ -29,6 +29,8 @@ Mesh::initialize(const StdVectorOfVec3d& vertices) { this->setInitialVertexPositions(vertices); this->setVertexPositions(vertices); + StdVectorOfVec3d disp = StdVectorOfVec3d(vertices.size(), imstk::Vec3d(0.0, 0.0, 0.0)); + this->setVertexDisplacements(disp); } void @@ -130,6 +132,7 @@ Mesh::setVertexDisplacements(const StdVectorOfVec3d& diff) void Mesh::setVertexDisplacements(const Vectord& u) { + assert(u.size() == 3 * m_vertexDisplacements.size()); size_t dofId = 0; for (auto &vDisp : m_vertexDisplacements) { @@ -143,6 +146,19 @@ Mesh::setVertexDisplacements(const Vectord& u) } } +void Mesh::translateVertices(const Vec3d& t) +{ + for (auto &vDisp : m_vertexDisplacements) + { + vDisp += t; + } + + for (size_t i = 0; i < m_vertexPositions.size(); ++i) + { + m_vertexPositions[i] = m_initialVertexPositions[i] + m_vertexDisplacements[i]; + } +} + const StdVectorOfVec3d& Mesh::getVertexDisplacements() const { diff --git a/Base/Geometry/Mesh/imstkMesh.h b/Base/Geometry/Mesh/imstkMesh.h index 3f3a4de911bba03067281c6fd6e430bf204077ba..8e3e15610785443abbbab3c78a5f5627150d1801 100644 --- a/Base/Geometry/Mesh/imstkMesh.h +++ b/Base/Geometry/Mesh/imstkMesh.h @@ -108,6 +108,11 @@ public: /// void setVertexDisplacements(const Vectord& u); + /// + /// \brief Deep translation of vertices using the given 3D vector + /// + void translateVertices(const Vec3d& t); + /// /// \brief Returns the vector displacements of mesh vertices /// diff --git a/CMakeLists.txt b/CMakeLists.txt index 3e0926635160e88fdc97dbe20a721e83acf9d6d2..53d4085603874d009836bd1710d1ae6d42f1879f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -180,6 +180,11 @@ if(BUILD_TESTING) include_directories(${GoogleMock_INCLUDE_DIRS}) endif() +# External data +if(BUILD_TESTING OR BUILD_EXAMPLES ) + include(imstkExternalData) +endif() + #-------------------------------------------------------------------------- # Add Source code subdirectories #-------------------------------------------------------------------------- diff --git a/Examples/CMakeLists.txt b/Examples/CMakeLists.txt index 35a25ae2e05b13f32451e626f309e6f85207defd..eeb48c990999090b98d602aaf389b4aa2f3d4bad 100644 --- a/Examples/CMakeLists.txt +++ b/Examples/CMakeLists.txt @@ -1,8 +1,3 @@ -#----------------------------------------------------------------------------- -# ExternalData module -#----------------------------------------------------------------------------- -include(imstkExternalData) - #----------------------------------------------------------------------------- # Add ExternalData #-----------------------------------------------------------------------------