An update will be applied December 9th, between 12PM and 1:00PM EST (UTC -5:00). The site may be slow during that time.

Commit 52a44943 authored by Andrew Wilson's avatar Andrew Wilson
Browse files

Merge conflicts

parents d1fe44aa 4f24afe0
Pipeline #240370 failed with stage
......@@ -50,10 +50,11 @@ function(imstk_add_test_internal target kind)
# Link test driver against current target, gtest and pthread
target_link_libraries(${test_driver_executable}
${target}
Testing
Threads::Threads
GTest::gtest
GTest::gmock
GTest::gtest_main
Threads::Threads
)
if (MSVC)
......
......@@ -16,7 +16,8 @@ set(iMSTK_BUILD_TESTING @iMSTK_BUILD_TESTING@)
set(iMSTK_USE_PHYSX @iMSTK_USE_PHYSX@)
# Use the iMSTK modules to find all required packages
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/modules")
set(CACHE_CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH})
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/modules")
include(${CMAKE_CURRENT_LIST_DIR}/modules/imstkFind.cmake)
include(CMakeFindDependencyMacro)
set(CMAKE_DEBUG_POSTFIX @CMAKE_DEBUG_POSTFIX@)
......@@ -122,4 +123,5 @@ find_dependency(VTK COMPONENTS
find_dependency(VTK COMPONENTS ${VTK_DEPENDENCIES})
if(iMSTK_USE_VTK_OSMESA)
add_definitions(-DiMSTK_USE_VTK_OSMESA)
endif()
\ No newline at end of file
endif()
set(CMAKE_MODULE_PATH ${CACHE_CMAKE_MODULE_PATH})
\ No newline at end of file
......@@ -373,6 +373,7 @@ add_subdirectory(Source/CollisionDetection)
add_subdirectory(Source/CollisionHandling)
add_subdirectory(Source/Scene)
add_subdirectory(Source/SimulationManager)
add_subdirectory(Source/Testing)
add_subdirectory(Source/Filtering)
add_subdirectory(Source/FilteringCore)
......
......@@ -198,7 +198,6 @@ makeLegs(const std::string& name)
bounds[4] = min[2] - size[2] * 0.25;
bounds[5] = max[2] + size[2] * 0.25;
computeSdf->setBounds(bounds);
computeSdf->setUseBounds(true);
computeSdf->update();
LOG(INFO) << "SDF Complete";
legsObj->setCollidingGeometry(std::make_shared<SignedDistanceField>(computeSdf->getOutputImage()));
......
......@@ -12,4 +12,11 @@ imstk_add_library( Filtering
${cppFiles}
DEPENDS
FilteringCore
${VTK_LIBRARIES})
\ No newline at end of file
${VTK_LIBRARIES})
#-----------------------------------------------------------------------------
# Testing
#-----------------------------------------------------------------------------
if( ${PROJECT_NAME}_BUILD_TESTING )
add_subdirectory(Testing)
endif()
\ No newline at end of file
include(imstkAddTest)
imstk_add_test( Filtering )
\ No newline at end of file
......@@ -19,90 +19,61 @@
=========================================================================*/
#pragma once
#include "gtest/gtest.h"
#include "imstkGeometry.h"
#include "imstkMath.h"
#include "imstkGeometryUtilities.h"
#include "imstkImageData.h"
#include "imstkOrientedBox.h"
#include "imstkSurfaceMesh.h"
#include "imstkSurfaceMeshDistanceTransform.h"
#include <array>
#include <queue>
using namespace imstk;
#ifdef WIN32
#pragma warning( push )
#pragma warning( disable : 4201 )
#endif
TEST(SurfaceMeshDistanceTransformTest, FilterWithBounds)
{
auto mesh = GeometryUtils::toSurfaceMesh(std::make_shared<OrientedBox>());
#ifdef WIN32
#pragma warning( pop )
#endif
Vec3d lowerLeft;
Vec3d upperRight;
// Convert the image into SDF
mesh->computeBoundingBox(lowerLeft, upperRight, 5.0);
Vec6d bounds;
bounds << lowerLeft.x(), upperRight.x(), lowerLeft.y(), upperRight.y(), lowerLeft.z(), upperRight.z();
auto toSdf = std::make_shared<SurfaceMeshDistanceTransform>();
toSdf->setInputMesh(mesh);
namespace imstk
{
class Decal;
toSdf->setBounds(bounds);
class DecalPool : public Geometry
{
public:
///
/// \brief Constructor
///
DecalPool(unsigned int maxNumDecals = 128, const std::string& name = std::string(""));
///
/// \brief Deconstructor
///
virtual ~DecalPool() override = default;
///
/// \brief Returns the string representing the type name of the geometry
///
virtual const std::string getTypeName() const override { return "DecalPool"; }
public:
///
/// \brief Add a \ref Decal object to this pool
///
std::shared_ptr<Decal> addDecal();
///
/// \brief Remove a \ref Decal object to this pool
///
void removeDecal();
///
/// \brief Get all decals
///
std::deque<std::shared_ptr<Decal>>& getDecals();
///
/// \brief Set/Get recyle
///
void setRecycle(bool recycle);
bool getRecycle();
///
/// \brief Get the number of decals
///
unsigned int getNumDecals();
///
/// \brief Get the max number of decals
///
unsigned int getMaxNumDecals();
protected:
std::deque<std::shared_ptr<Decal>> m_orderedDecals;
std::deque<std::shared_ptr<Decal>> m_freeDecals;
void applyTransform(const Mat4d& imstkNotUsed(m)) override { }
virtual void updatePostTransformData() const override { }
unsigned int m_maxNumDecals;
unsigned int m_numDecals = 0;
bool m_recycle = true;
Vec3d m_vertexPositions[8];
Vec3i m_triangles[12];
};
auto dimensions = Vec3i{ 4, 5, 6 };
toSdf->setDimensions(dimensions);
toSdf->setTolerance(1.0e-9);
toSdf->update();
auto image = toSdf->getOutputImage();
EXPECT_EQ(dimensions, image->getDimensions());
EXPECT_TRUE(bounds.isApprox(image->getBounds()));
}
TEST(SurfaceMeshDistanceTransformTest, FilterWithoutBounds)
{
auto mesh = GeometryUtils::toSurfaceMesh(std::make_shared<OrientedBox>());
auto toSdf = std::make_shared<SurfaceMeshDistanceTransform>();
toSdf->setInputMesh(mesh);
auto dimensions = Vec3i{ 4, 5, 6 };
toSdf->setDimensions(dimensions);
toSdf->setTolerance(1.0e-9);
toSdf->update();
auto image = toSdf->getOutputImage();
Vec3d lowerLeft;
Vec3d upperRight;
mesh->computeBoundingBox(lowerLeft, upperRight);
Vec6d bounds;
bounds << lowerLeft.x(), upperRight.x(), lowerLeft.y(), upperRight.y(), lowerLeft.z(), upperRight.z();
EXPECT_EQ(dimensions, image->getDimensions());
EXPECT_TRUE(bounds.isApprox(image->getBounds()));
}
\ No newline at end of file
......@@ -221,6 +221,26 @@ SurfaceMeshDistanceTransform::getOutputImage()
return std::dynamic_pointer_cast<ImageData>(getOutput());
}
void
SurfaceMeshDistanceTransform::setBounds(const Vec6d& bounds)
{
m_Bounds = bounds;
if (m_Bounds.isZero())
{
LOG(WARNING) << "Bounds are zero, the image bounds will be used instead.";
}
}
void
SurfaceMeshDistanceTransform::setBounds(const Vec3d& min, const Vec3d& max)
{
m_Bounds << min.x(), max.x(), min.y(), max.y(), min.z(), max.z();
if (m_Bounds.isZero())
{
LOG(WARNING) << "Bounds are zero, the image bounds will be used instead.";
}
}
void
SurfaceMeshDistanceTransform::requestUpdate()
{
......@@ -239,29 +259,15 @@ SurfaceMeshDistanceTransform::requestUpdate()
return;
}
// Allocate an image for it
Vec3d min;
Vec3d max;
inputSurfaceMesh->computeBoundingBox(min, max);
double bounds[6];
if (m_UseBounds)
Vec6d bounds = m_Bounds;
if (bounds.isZero())
{
bounds[0] = m_Bounds[0];
bounds[1] = m_Bounds[1];
bounds[2] = m_Bounds[2];
bounds[3] = m_Bounds[3];
bounds[4] = m_Bounds[4];
bounds[5] = m_Bounds[5];
}
else
{
bounds[0] = min[0];
bounds[1] = max[0];
bounds[2] = min[1];
bounds[3] = max[1];
bounds[4] = min[2];
bounds[5] = max[2];
Vec3d min, max;
inputSurfaceMesh->computeBoundingBox(min, max, 0.0);
bounds << min.x(), max.x(), min.y(), max.y(), min.z(), max.z();
LOG(WARNING) << "Bounds are zero, the image bounds + " << bounds.transpose() << "will be used.";
}
const Vec3d size = Vec3d(bounds[1] - bounds[0], bounds[3] - bounds[2], bounds[5] - bounds[4]);
const Vec3d spacing = size.cwiseQuotient(m_Dimensions.cast<double>());
const Vec3d origin = Vec3d(bounds[0], bounds[2], bounds[4]);
......
......@@ -32,9 +32,11 @@ class SurfaceMesh;
/// \class SurfaceMeshDistanceTransform
///
/// \brief This filter computes exact signed distance fields using octrees
/// and psuedonormal computations. One might need to adjust the tolerance
/// and pseudonormal computations. One might need to adjust the tolerance
/// depending on dataset scale.
///
/// The bounds for the image can be set in the filter, when none are set
/// the bounding box of the mesh is used, the margin. When providing your own bounds a
/// box larger than the original object might be necessary depending on shape
class SurfaceMeshDistanceTransform : public GeometryAlgorithm
{
public:
......@@ -49,50 +51,53 @@ public:
std::shared_ptr<ImageData> getOutputImage();
imstkGetMacro(Dimensions, const Vec3i&);
imstkGetMacro(Bounds, const Vec6d&);
imstkGetMacro(UseBounds, bool);
imstkGetMacro(NarrowBanded, bool);
imstkGetMacro(DilateSize, int);
imstkGetMacro(Tolerance, double);
///
/// \brief Dimensions of distance transform to fill
///
///@{
imstkSetMacro(Dimensions, const Vec3i&);
void setDimensions(int dimX, int dimY, int dimZ) { setDimensions(Vec3i(dimX, dimY, dimZ)); }
imstkGetMacro(Dimensions, const Vec3i&);
///@}
///
/// \brief Optionally one may specify bounds, if not specified
/// bounds of the input SurfaceMesh is used
///
imstkSetMacro(Bounds, const Vec6d&);
imstkSetMacro(UseBounds, bool);
/// note Vec6d is be of the format [minX, maxX, minY, maxY, minZ, maxZ]
///@{
void setBounds(const Vec3d& min, const Vec3d& max);
void setBounds(const Vec6d&);
imstkGetMacro(Bounds, const Vec6d&);
///@}
///
/// \brief If on, will compute only a narrow banded transform
///
///@{
imstkSetMacro(NarrowBanded, bool);
imstkGetMacro(NarrowBanded, bool);
///@}
///
/// \brief Width of the band
///
///@{
imstkSetMacro(DilateSize, int);
imstkGetMacro(DilateSize, int);
///@}
///@{
imstkSetMacro(Tolerance, double);
void setDimensions(int dimX, int dimY, int dimZ) { setDimensions(Vec3i(dimX, dimY, dimZ)); }
imstkGetMacro(Tolerance, double);
///@}
protected:
void requestUpdate() override;
private:
Vec3i m_Dimensions = Vec3i(0, 0, 0);
Vec6d m_Bounds;
bool m_UseBounds = false;
double m_Tolerance = 1.0e-10;
Vec3i m_Dimensions = Vec3i::Zero();
Vec6d m_Bounds = Vec6d::Zero();
double m_Tolerance = 1.0e-10;
int m_DilateSize = 4; ///> Only for narrow banded
bool m_NarrowBanded = false;
int m_DilateSize = 4; ///< Only for narrow banded
};
}
\ No newline at end of file
/*=========================================================================
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.
=========================================================================*/
#pragma once
#include "imstkAnalyticalGeometry.h"
namespace imstk
{
class Decal : public AnalyticalGeometry
{
public:
Decal(const std::string& name = std::string(""));
virtual ~Decal() override = default;
///
/// \brief Returns the string representing the type name of the geometry
///
virtual const std::string getTypeName() const override { return "Decal"; }
public:
///
/// \brief Print the cube info
///
void print() const override;
///
/// \brief Returns the volume of the cube
///
double getVolume() override { return m_dimensions[0] * m_dimensions[1] * m_dimensions[2]; }
///
/// \brief Update decal transforms
///
void updateDecal(Mat4d& viewMatrix);
protected:
// Hide these functions
using AnalyticalGeometry::getFunctionValue;
void applyTransform(const Mat4d& m) override;
Vec3d m_dimensions;
Mat4d m_inverse;
};
}
/*=========================================================================
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 "imstkDecalPool.h"
#include "imstkDecal.h"
#include "imstkLogger.h"
namespace imstk
{
DecalPool::DecalPool(unsigned int maxNumDecals /*= 128*/, const std::string& name)
: Geometry(name)
{
if (maxNumDecals <= 128)
{
m_maxNumDecals = maxNumDecals;
}
else
{
m_maxNumDecals = 128;
LOG(WARNING) << "The maximum number of decals is 128";
}
m_vertexPositions[0] = Vec3d(0.5, 0.5, 0.5);
m_vertexPositions[1] = Vec3d(0.5, 0.5, -0.5);
m_vertexPositions[2] = Vec3d(0.5, -0.5, 0.5);
m_vertexPositions[3] = Vec3d(0.5, -0.5, -0.5);
m_vertexPositions[4] = Vec3d(-0.5, 0.5, 0.5);
m_vertexPositions[5] = Vec3d(-0.5, 0.5, -0.5);
m_vertexPositions[6] = Vec3d(-0.5, -0.5, 0.5);
m_vertexPositions[7] = Vec3d(-0.5, -0.5, -0.5);
m_triangles[0] = Vec3i(2, 1, 0);
m_triangles[1] = Vec3i(1, 2, 3);
m_triangles[2] = Vec3i(4, 5, 6);
m_triangles[3] = Vec3i(7, 6, 5);
m_triangles[4] = Vec3i(0, 1, 4);
m_triangles[5] = Vec3i(5, 4, 1);
m_triangles[6] = Vec3i(6, 3, 2);
m_triangles[7] = Vec3i(3, 6, 7);
m_triangles[8] = Vec3i(4, 2, 0);
m_triangles[9] = Vec3i(2, 4, 6);
m_triangles[10] = Vec3i(1, 3, 5);
m_triangles[11] = Vec3i(7, 5, 3);
for (unsigned int i = 0; i < maxNumDecals; i++)
{
m_freeDecals.push_back(std::make_shared<Decal>("Decal-" + std::to_string(i)));
}
}
std::shared_ptr<Decal>
DecalPool::addDecal()
{
if (m_numDecals >= m_maxNumDecals && !m_recycle)
{
LOG(WARNING) << "Decal pool exhausted, unable to add more decals";
return nullptr;
}
if (m_recycle && m_numDecals >= m_maxNumDecals)
{
m_freeDecals.push_back(m_orderedDecals.front());
m_orderedDecals.pop_front();
}
auto decal = m_freeDecals.front();
m_orderedDecals.push_back(decal);
m_freeDecals.pop_front();
if (m_numDecals < m_maxNumDecals)
{
m_numDecals++;
}
return decal;
}
void
DecalPool::removeDecal()
{
m_freeDecals.push_back(m_orderedDecals.front());
m_orderedDecals.pop_front();
m_numDecals--;
}
std::deque<std::shared_ptr<Decal>>&
DecalPool::getDecals()
{
return m_orderedDecals;
}
void
DecalPool::setRecycle(bool recycle)
{
m_recycle = recycle;
}
bool
DecalPool::getRecycle()
{
return m_recycle;
}
unsigned int
DecalPool::getNumDecals()
{
return m_numDecals;
}
unsigned int
DecalPool::getMaxNumDecals()
{
return m_maxNumDecals;
}
}
#-----------------------------------------------------------------------------
# Create target
#-----------------------------------------------------------------------------
if( ${PROJECT_NAME}_BUILD_TESTING )
include(imstkAddLibrary)
imstk_add_library( Testing
DEPENDS
Common
GTest::gtest
${VTK_LIBRARIES}
)
endif()
\ No newline at end of file
......@@ -19,38 +19,33 @@
=========================================================================*/
#include "imstkDecal.h"
#include "imstkLogger.h"
#include <vtksys/SystemTools.hxx>
namespace imstk
{
Decal::Decal(const std::string& name) : AnalyticalGeometry(name),
m_dimensions(Vec3d(1.0, 1.0, 1.0))
{
}
#include <gtest/gtest.h>
void
Decal::print() const
{
Geometry::print();
LOG(INFO) << "Dimensions: " << m_dimensions[0]
<< ", " << m_dimensions[1]
<< ", " << m_dimensions[2];
}
void
Decal::applyTransform(const Mat4d& m)
{