diff --git a/CMake/External/CMakeLists.txt b/CMake/External/CMakeLists.txt index 7a84bfba365d80e03e33e5c11e2787accaa7245f..166bf7059c8e190d6d19d4d7ed79af3f17c80684 100644 --- a/CMake/External/CMakeLists.txt +++ b/CMake/External/CMakeLists.txt @@ -95,7 +95,7 @@ ExternalProject_Add( ${PROJECT_NAME} -D${PROJECT_NAME}_BUILD_EXAMPLES:BOOL=${${PROJECT_NAME}_BUILD_EXAMPLES} -D${PROJECT_NAME}_BUILD_TESTING:BOOL=${${PROJECT_NAME}_BUILD_TESTING} -D${PROJECT_NAME}_USE_OpenHaptics:BOOL=${${PROJECT_NAME}_USE_OpenHaptics} - -D${PROJECT_NAME}_USE_MODEL_REDUCTION:BOOL={${PROJECT_NAME}_USE_MODEL_REDUCTION} + -D${PROJECT_NAME}_USE_MODEL_REDUCTION:BOOL=${${PROJECT_NAME}_USE_MODEL_REDUCTION} -D${PROJECT_NAME}_USE_Vulkan:BOOL=${${PROJECT_NAME}_USE_Vulkan} -D${PROJECT_NAME}_ENABLE_AUDIO:BOOL=${${PROJECT_NAME}_ENABLE_AUDIO} -D${PROJECT_NAME}_ENABLE_VR:BOOL=${${PROJECT_NAME}_ENABLE_VR} diff --git a/CMake/External/External_Eigen3.cmake b/CMake/External/External_Eigen3.cmake index f86d8b8f7324c1c37e15bff616ac944f64e72c3e..7d19d5e75158471d8190680ccbcb6d8b3a3e7201 100644 --- a/CMake/External/External_Eigen3.cmake +++ b/CMake/External/External_Eigen3.cmake @@ -3,7 +3,7 @@ #----------------------------------------------------------------------------- include(imstkAddExternalProject) imstk_add_external_project( Eigen3 - URL "https://gitlab.com/libeigen/eigen/-/archive/3.3.7/eigen-3.3.7.tar.gz" + URL "https://gitlab.kitware.com/iMSTK/eigen/-/archive/3.3.7/eigen-3.3.7.tar.gz" URL_HASH MD5=9e30f67e8531477de4117506fe44669b CMAKE_CACHE_ARGS -DBUILD_TESTING:BOOL=OFF diff --git a/CMake/External/External_GTest.cmake b/CMake/External/External_GTest.cmake index 2e3919db28bfaea740106c071da38dbeca963f82..2fe9d9757da31e54dbe4aa409503ad35acbc4f2b 100644 --- a/CMake/External/External_GTest.cmake +++ b/CMake/External/External_GTest.cmake @@ -3,8 +3,8 @@ #----------------------------------------------------------------------------- include(imstkAddExternalProject) imstk_add_external_project( GTest - URL https://github.com/google/googletest/archive/release-1.10.0.zip - URL_MD5 82358affdd7ab94854c8ee73a180fc53 + URL https://gitlab.kitware.com/iMSTK/googletest/-/archive/release-1.10.0/googletest-release-1.10.0.zip + URL_MD5 1878d0300f865cb54df06b220ded5168 CMAKE_CACHE_ARGS -DBUILD_GMOCK:BOOL=ON -DBUILD_GTEST:BOOL=ON diff --git a/CMake/External/External_VTK.cmake b/CMake/External/External_VTK.cmake index 7b69e0068ca24015a26f994ee53cfd83fcc43e30..03cb81629292f5fa76a9c73d6cbde45da50d614b 100644 --- a/CMake/External/External_VTK.cmake +++ b/CMake/External/External_VTK.cmake @@ -1,13 +1,7 @@ #----------------------------------------------------------------------------- # Dependencies #----------------------------------------------------------------------------- -set(VTK_DEPENDENCIES "") -set(VTK_ENABLE_OPENVR "NO") -if(${${PROJECT_NAME}_ENABLE_VR}) - list(APPEND VTK_DEPENDENCIES "openvr") - set(VTK_ENABLE_OPENVR "YES") -endif() - +set(VTK_DEPENDENCIES "openvr") set(${PROJECT_NAME}_VTK_REPO_SOURCE "9.0" CACHE STRING "Select VTK Source Branch/Tag") set(VTK_SOURCES "9.0;master;release;nightly-master" CACHE INTERNAL "List of available VTK branch,tags to get") @@ -15,8 +9,12 @@ set_property(CACHE ${PROJECT_NAME}_VTK_REPO_SOURCE PROPERTY STRINGS ${VTK_SOURCE set(VTK_MODULE_SETTINGS -DVTK_MODULE_ENABLE_VTK_ChartsCore:STRING=YES + -DVTK_MODULE_ENABLE_VTK_FiltersCore:STRING=YES -DVTK_MODULE_ENABLE_VTK_FiltersExtraction:STRING=YES + -DVTK_MODULE_ENABLE_VTK_FiltersGeneral:STRING=YES -DVTK_MODULE_ENABLE_VTK_FiltersModeling:STRING=YES + -DVTK_MODULE_ENABLE_VTK_ImagingGeneral:STRING=YES + -DVTK_MODULE_ENABLE_VTK_ImagingStencil:STRING=YES -DVTK_MODULE_ENABLE_VTK_IOExport:STRING=YES -DVTK_MODULE_ENABLE_VTK_IOGeometry:STRING=YES -DVTK_MODULE_ENABLE_VTK_IOImport:STRING=YES @@ -31,14 +29,18 @@ set(VTK_MODULE_SETTINGS -DVTK_MODULE_ENABLE_VTK_RenderingContext2D:STRING=YES -DVTK_MODULE_ENABLE_VTK_RenderingContextOpenGL2:STRING=YES -DVTK_MODULE_ENABLE_VTK_RenderingOpenGL2:STRING=YES - -DVTK_MODULE_ENABLE_VTK_RenderingOpenVR:STRING=${VTK_ENABLE_OPENVR} + -DVTK_MODULE_ENABLE_VTK_RenderingOpenVR:STRING=YES -DVTK_MODULE_ENABLE_VTK_RenderingVolumeOpenGL2:STRING=YES -DVTK_MODULE_ENABLE_VTK_ViewsContext2D:STRING=YES -DVTK_MODULE_ENABLE_VTK_glew:STRING=YES -DVTK_BUILD_EXAMPLES:STRING=DONT_WANT -DVTK_BUILD_TESTING:STRING=OFF -DVTK_GROUP_ENABLE_StandAlone:STRING=DONT_WANT - -DVTK_GROUP_ENABLE_Rendering:STRING=DONT_WANT) + -DVTK_GROUP_ENABLE_Rendering:STRING=DONT_WANT + ) +if (${PROJECT_NAME}_USE_VTK_OSMESA) + list(APPEND VTK_MODULE_SETTINGS -DVTK_DEFAULT_RENDER_WINDOW_OFFSCREEN=1 -DVTK_OPENGL_HAS_OSMESA=1 -DVTK_USE_COCOA=0 -DVTK_USE_X=0) +endif() set(${PROJECT_NAME}_VTK_SOURCE GIT_REPOSITORY https://gitlab.kitware.com/vtk/vtk.git) if(${PROJECT_NAME}_VTK_REPO_SOURCE EQUAL "9.0") diff --git a/CMake/External/External_glfw.cmake b/CMake/External/External_glfw.cmake index ee9acff818f7466812519503db6a5b20acf45433..ade86cf630d32bbdb0961ed0bf84a90beaa37dd7 100644 --- a/CMake/External/External_glfw.cmake +++ b/CMake/External/External_glfw.cmake @@ -3,7 +3,7 @@ #----------------------------------------------------------------------------- include(imstkAddExternalProject) imstk_add_external_project( glfw - URL https://github.com/glfw/glfw/archive/3.2.1.zip + URL https://gitlab.kitware.com/iMSTK/glfw/-/archive/3.2.1/glfw-3.2.1.zip URL_MD5 cb412cba8daba35d849ddfe78700a210 CMAKE_ARGS -DGLFW_BUILD_DOCS:BOOL=OFF diff --git a/CMake/External/External_openvr.cmake b/CMake/External/External_openvr.cmake index 2437d8b4e2580eb62afeaf9c3ef81498d6c71d0a..b83957b23948ca7799be43696402435fac10ef78 100644 --- a/CMake/External/External_openvr.cmake +++ b/CMake/External/External_openvr.cmake @@ -1,4 +1,3 @@ -set(_version "1.0.9") #----------------------------------------------------------------------------- # Set project prefix path #----------------------------------------------------------------------------- @@ -51,8 +50,8 @@ set(copy_openvr_lib_command #----------------------------------------------------------------------------- include(imstkAddExternalProject) imstk_add_external_project( openvr - URL "https://github.com/ValveSoftware/openvr/archive/v${_version}.tar.gz" - URL_MD5 "0de39e805155cf4e0e907bb181924c48" + URL "https://gitlab.kitware.com/iMSTK/openvr/-/archive/v1.12.5/openvr-v1.12.5.tar.gz" + URL_MD5 "42c4d1c4a194860aaa4e793b009b99c0" DOWNLOAD_DIR ${OPENVR_PREFIX} SOURCE_DIR ${OPENVR_EXTRACT_DIR} BINARY_DIR ${OPENVR_EXTRACT_DIR} diff --git a/CMake/Utilities/imstkAddLibrary.cmake b/CMake/Utilities/imstkAddLibrary.cmake index f124ed858ef0cdad7c997f7ee9997fd1e6b5ddfb..41901e34ae2560f7c77b68dad47003a13e85c274 100644 --- a/CMake/Utilities/imstkAddLibrary.cmake +++ b/CMake/Utilities/imstkAddLibrary.cmake @@ -93,7 +93,7 @@ function(imstk_add_library target) #----------------------------------------------------------------------------- target_compile_options(${target} PRIVATE $<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:GNU>>: - -Wall> + -Wall -Wno-unused-function> $<$<CXX_COMPILER_ID:MSVC>: -W4 -MP>) diff --git a/CMake/iMSTKConfig.cmake.in b/CMake/iMSTKConfig.cmake.in index 641e239b5325ab2fcdfb179cd1581a6743896b4b..4df73501ad856831d1baa623685713f927e45d94 100644 --- a/CMake/iMSTKConfig.cmake.in +++ b/CMake/iMSTKConfig.cmake.in @@ -55,14 +55,11 @@ find_package( LibNiFalcon REQUIRED) find_package( Libusb REQUIRED) # OpenVR -if(iMSTK_ENABLE_VR) - add_definitions( -DiMSTK_ENABLE_VR ) - find_package( openvr REQUIRED ) -endif() +find_package( openvr REQUIRED ) # PhysX find_package(PhysX REQUIRED) -# + #SCCD find_package( SCCD REQUIRED ) @@ -90,36 +87,41 @@ if(iMSTK_USE_OpenHaptics) endif() # VTK +list(GET OPENVR_INCLUDE_DIRS 0 OpenVR_INCLUDE_DIR) +list(GET OPENVR_LIBRARIES 1 OpenVR_LIBRARY) +set(OpenVR_INCLUDE_DIR ${OpenVR_INCLUDE_DIR} CACHE INTERNAL "") +set(OpenVR_LIBRARY ${OpenVR_LIBRARY} CACHE INTERNAL "") set(VTK_DIR @VTK_DIR@) find_dependency(VTK CONFIG) # modules are linked via `VTK::CommonCore` # vtk_module_autoinit is needed -list(APPEND VTK_DEPENDENCIES +find_dependency(VTK COMPONENTS ChartsCore CommonCore CommonDataModel + FiltersCore + FiltersExtraction FiltersGeneral - FiltersSources FiltersModeling - FiltersExtraction + FiltersSources IOExport IOImport IOPLY IOParallel IOParallelXML ImagingCore + ImagingGeneral + ImagingStencil InteractionStyle RenderingAnnotation RenderingContext2D RenderingContextOpenGL2 RenderingCore RenderingOpenGL2 + RenderingOpenVR RenderingVolume RenderingVolumeOpenGL2 ViewsContext2D) -if (${PROJECT_NAME}_ENABLE_VR) - list(APPEND VTK_DEPENDENCIES vtkRenderingOpenVR) -endif() find_dependency(VTK COMPONENTS ${VTK_DEPENDENCIES}) # glfw, gli diff --git a/CMakeLists.txt b/CMakeLists.txt index f344847c01c7a62d93e6b6cad555655379ade6e7..e5713ed7d95203806a0aad46fd6fd668c9569773 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -89,6 +89,11 @@ if (${PROJECT_NAME}_BUILD_TESTING) set(BUILD_TESTING ON) endif () option(${PROJECT_NAME}_USE_MODEL_REDUCTION "Build with model reduction, requires a VegaFEM built with Intel MKL and arpack" OFF) +option(${PROJECT_NAME}_USE_VTK_OSMESA "Build with VTK OSMesa rendering" OFF) +if (${${PROJECT_NAME}_USE_VTK_OSMESA} AND NOT UNIX) + message(WARNING "OSMesa only works on unix, building without") + set(${PROJECT_NAME}_USE_VTK_OSMESA FALSE CACHE BOOL "Build with VTK OSMesa rendering" FORCE) +endif() #----------------------------------------------------------------------------- # CTest/Dashboards @@ -139,6 +144,7 @@ if(${PROJECT_NAME}_SUPERBUILD) imstk_define_dependency(glm) imstk_define_dependency(imgui) imstk_define_dependency(LibNiFalcon) + imstk_define_dependency(openvr) imstk_define_dependency(PhysX) imstk_define_dependency(SCCD) imstk_define_dependency(tbb) @@ -166,12 +172,6 @@ if(${PROJECT_NAME}_SUPERBUILD) imstk_define_dependency(Vulkan) endif() - option(${PROJECT_NAME}_ENABLE_VR "Allow the usage of VR rendering." OFF) - - if(${PROJECT_NAME}_ENABLE_VR) - imstk_define_dependency(openvr) - endif() - if(${PROJECT_NAME}_BUILD_TESTING) imstk_define_dependency(GTest) @@ -234,14 +234,8 @@ find_package( imgui REQUIRED ) find_package( LibNiFalcon REQUIRED) # Libusb find_package( Libusb REQUIRED) - # OpenVR -if(${PROJECT_NAME}_ENABLE_VR) - add_definitions( -DiMSTK_ENABLE_VR ) - find_package( openvr REQUIRED ) -else() - remove_definitions( -DiMSTK_ENABLE_VR ) -endif() +find_package( openvr REQUIRED ) # Select the release version of PhysX to use set(PHYSX_CONFIGURATION "${PHYSX_CONFIGURATION}" CACHE STRING "Select PhysX Library Type for Release and RelWithDebInfo builds") @@ -292,28 +286,29 @@ list(APPEND VTK_DEPENDENCIES ChartsCore CommonCore CommonDataModel + FiltersCore + FiltersExtraction FiltersGeneral - FiltersSources FiltersModeling - FiltersExtraction + FiltersSources IOExport IOImport IOPLY IOParallel IOParallelXML ImagingCore + ImagingGeneral + ImagingStencil InteractionStyle RenderingAnnotation RenderingContext2D RenderingContextOpenGL2 RenderingCore RenderingOpenGL2 + RenderingOpenVR RenderingVolume RenderingVolumeOpenGL2 ViewsContext2D) -if (${PROJECT_NAME}_ENABLE_VR) - list(APPEND VTK_DEPENDENCIES vtkRenderingOpenVR) -endif() find_package(VTK COMPONENTS ${VTK_DEPENDENCIES}) # Vulkan @@ -400,6 +395,7 @@ add_subdirectory(Source/Scene) add_subdirectory(Source/SimulationManager) add_subdirectory(Source/apiUtilities) add_subdirectory(Source/Pulse) +add_subdirectory(Source/Filtering) #-------------------------------------------------------------------------- # Add Examples subdirectories diff --git a/Data/Surgical Instruments/Scalpel/Scalpel_Albedo.png.sha512 b/Data/Surgical Instruments/Scalpel/Scalpel_Albedo.png.sha512 new file mode 100644 index 0000000000000000000000000000000000000000..76e8554bbf01c84865ed830d051f81308cd689e6 --- /dev/null +++ b/Data/Surgical Instruments/Scalpel/Scalpel_Albedo.png.sha512 @@ -0,0 +1 @@ +ad0495eb4b68162adeff1cd199ae87896e1cb9707d99109160fc339fc06b7410b629d4044d537e632d4b30c2c170def129c2f729e5fb3ef9441f7a6c32c35e4d \ No newline at end of file diff --git a/Data/Surgical Instruments/Scalpel/Scalpel_Blade10.obj.sha512 b/Data/Surgical Instruments/Scalpel/Scalpel_Blade10.obj.sha512 new file mode 100644 index 0000000000000000000000000000000000000000..4d0197c17e91a3af9101aff5b126a33e527dee41 --- /dev/null +++ b/Data/Surgical Instruments/Scalpel/Scalpel_Blade10.obj.sha512 @@ -0,0 +1 @@ +b3020f808f1589756d438d689bfde4ef673a3ab51f93f699bb7c16dbefc21fd48bdd5660810c509f5bfa4256bb4fa2aa8955c3b59ca011e24c72414890291616 \ No newline at end of file diff --git a/Data/Surgical Instruments/Scalpel/Scalpel_Blade10_Hull.stl.sha512 b/Data/Surgical Instruments/Scalpel/Scalpel_Blade10_Hull.stl.sha512 new file mode 100644 index 0000000000000000000000000000000000000000..034890c59bc0acf07d468a2df98bf4f7a7f59fcd --- /dev/null +++ b/Data/Surgical Instruments/Scalpel/Scalpel_Blade10_Hull.stl.sha512 @@ -0,0 +1 @@ +3314f75a94b2ea8b026053678f3754e5203dd90b35e80f99e4ae83f38957461b9ab0f4fbb60c94240f3e6622a99ee4a1929e8d98b29e02b894c03da9a716f4c9 \ No newline at end of file diff --git a/Data/Surgical Instruments/Scalpel/Scalpel_Blade11.obj.sha512 b/Data/Surgical Instruments/Scalpel/Scalpel_Blade11.obj.sha512 new file mode 100644 index 0000000000000000000000000000000000000000..6f0e02f90ebf77c320736922db2c8a09e9ee35fb --- /dev/null +++ b/Data/Surgical Instruments/Scalpel/Scalpel_Blade11.obj.sha512 @@ -0,0 +1 @@ +a68a897914f25b37381a833da42e1efd6242f3f43b3f3be3d53662151e41819a3b467d86884e199933364a5e3e09fe3999dd763b8ee9282cdd9e664f9ba1cf66 \ No newline at end of file diff --git a/Data/Surgical Instruments/Scalpel/Scalpel_Blade15.obj.sha512 b/Data/Surgical Instruments/Scalpel/Scalpel_Blade15.obj.sha512 new file mode 100644 index 0000000000000000000000000000000000000000..85bace8d1d48801ab5bd52ac739552d7d6b66c8a --- /dev/null +++ b/Data/Surgical Instruments/Scalpel/Scalpel_Blade15.obj.sha512 @@ -0,0 +1 @@ +53c94e1d26114f36ad553fa6de26d6bdd1d9ccb7b693b4560ac25a520ce60f17fbd5819aba5d7c7580ca2c1875665439744b39f6f3a530138f2af9409a110f37 \ No newline at end of file diff --git a/Data/Surgical Instruments/Scalpel/Scalpel_Handle.obj.sha512 b/Data/Surgical Instruments/Scalpel/Scalpel_Handle.obj.sha512 new file mode 100644 index 0000000000000000000000000000000000000000..8e87f96ea38351bdcf2829fdb54a10d85ed1dd99 --- /dev/null +++ b/Data/Surgical Instruments/Scalpel/Scalpel_Handle.obj.sha512 @@ -0,0 +1 @@ +5bfa843d28651bf9e1573d627434905ca7980541877c9a2aa3cd24d3c85f914245a416340de3d22cdeba73d641daf23d7aab9be753072c7c40e875f688ce506a \ No newline at end of file diff --git a/Data/legs/femoralArtery.stl.sha512 b/Data/legs/femoralArtery.stl.sha512 new file mode 100644 index 0000000000000000000000000000000000000000..38f05c91be8f057de0050bad71eb6c4a779e0a37 --- /dev/null +++ b/Data/legs/femoralArtery.stl.sha512 @@ -0,0 +1 @@ +0ef3e5b862501a2988de967f04e37ad37661819ea153b4cd2d26ebc89df287bf5a04bf3f3ac3faf3a7d7fed8009a127a7637f63869ffd3627efcd9cd6099fafc \ No newline at end of file diff --git a/Data/legs/femoralArteryCut.stl.sha512 b/Data/legs/femoralArteryCut.stl.sha512 new file mode 100644 index 0000000000000000000000000000000000000000..bb7284da5bb9197475e73969e2c14b9e9ed4c9f3 --- /dev/null +++ b/Data/legs/femoralArteryCut.stl.sha512 @@ -0,0 +1 @@ +e16c4335d3020f8540843f3c6b4f769304eb44e10e9181ddf30ad30297e87e89680f73dae86238b51e10d3248c8b64c8c4e62966302a141aaf51bbf8ab3ac79f \ No newline at end of file diff --git a/Data/legs/femurBone.stl.sha512 b/Data/legs/femurBone.stl.sha512 new file mode 100644 index 0000000000000000000000000000000000000000..0a81cd0b9fde9675343ff8964c1f2e0f35150eda --- /dev/null +++ b/Data/legs/femurBone.stl.sha512 @@ -0,0 +1 @@ +0d8f71d9a75d32802ace47a2ea2f63c1dbd2cd15a286c59686a93bad9258dcea60042e682efb652ad4eb908df899982905cf284ab8292e9fd6d1fe847b7ac4b7 \ No newline at end of file diff --git a/Data/legs/femurBone_SDF.nii.sha512 b/Data/legs/femurBone_SDF.nii.sha512 new file mode 100644 index 0000000000000000000000000000000000000000..a9bc981d6eabd920b2161deb19114fe3e5ab2455 --- /dev/null +++ b/Data/legs/femurBone_SDF.nii.sha512 @@ -0,0 +1 @@ +777b16098845cca8d45f3254de1fb941c05a1c1b11619173e788e49c323f693d71f216e23063ca8ee340b26ba4fb58bf45988ff6dac974596e0c872b5251d904 \ No newline at end of file diff --git a/Data/legs/legsBones.stl.sha512 b/Data/legs/legsBones.stl.sha512 new file mode 100644 index 0000000000000000000000000000000000000000..c49859390b44361a1eec3931428b8b04980c21ca --- /dev/null +++ b/Data/legs/legsBones.stl.sha512 @@ -0,0 +1 @@ +bb4ec0204bcfecd346b6ff3c8b5cd6992d7f9507bce29e35b33be80236d29dc3d1c7197453cd724bf1dd0a10e714de2b1e0eee4d51dfe7b58216a52641271b7b \ No newline at end of file diff --git a/Data/legs/legsCutaway.stl.sha512 b/Data/legs/legsCutaway.stl.sha512 new file mode 100644 index 0000000000000000000000000000000000000000..6429fd6602f8b6b76e21ef4b23e0f8df5483d827 --- /dev/null +++ b/Data/legs/legsCutaway.stl.sha512 @@ -0,0 +1 @@ +8ad322ea48cffa1296af8cfb226e33e0a305ca95db9ec22ec101d93b3229c4a1b36244017ba4785aacd42fdb100f475cd2a66e901b03501a94bb2a907c1ee064 \ No newline at end of file diff --git a/Examples/Audio/AudioExample.cpp b/Examples/Audio/AudioExample.cpp index 8924f88f5f4e193930e39737dfe719941bf48adf..a66278b8ccce8b5ff2c6bf678d227520ff95dc4c 100644 --- a/Examples/Audio/AudioExample.cpp +++ b/Examples/Audio/AudioExample.cpp @@ -23,10 +23,7 @@ #include "imstkLogger.h" #ifdef iMSTK_AUDIO_ENABLED - -// Audio #include <SFML/Audio.hpp> - #endif using namespace imstk; @@ -41,10 +38,10 @@ playSound(const std::string& filename) CHECK(buffer.loadFromFile(filename)) << "testSound: Could not open the input sound file: " << filename; // Display sound informations - std::cout << filename << std::endl; - std::cout << " " << buffer.getDuration().asSeconds() << " seconds" << std::endl; - std::cout << " " << buffer.getSampleRate() << " samples / sec" << std::endl; - std::cout << " " << buffer.getChannelCount() << " channels" << std::endl; + LOG(INFO) << filename; + LOG(INFO) << " " << buffer.getDuration().asSeconds() << " seconds"; + LOG(INFO) << " " << buffer.getSampleRate() << " samples / sec"; + LOG(INFO) << " " << buffer.getChannelCount() << " channels"; // Create a sound instance and play it sf::Sound sound(buffer); @@ -66,11 +63,11 @@ playSound(const std::string& filename) sf::Listener::setPosition((float)listnerPos.x(), (float)listnerPos.y(), (float)listnerPos.z()); // Display the playing position - std::cout << "\rPlaying... " << sound.getPlayingOffset().asSeconds() << " sec "; - std::cout << std::flush; + LOG(INFO) << "\rPlaying... " << sound.getPlayingOffset().asSeconds() << " sec "; + LOG(INFO) << std::flush; } - std::cout << "\n" << std::endl; -#else if + LOG(INFO) << "\n"; +#else LOG(INFO) << "testSound: Audio is supported only on windows!"; #endif } @@ -85,10 +82,10 @@ playMusic(const std::string& filename) CHECK(music.openFromFile(filename)) << "playMusic: Could not open the input music file: " << filename; // Display music informations - std::cout << filename << ":" << std::endl; - std::cout << " " << music.getDuration().asSeconds() << " seconds" << std::endl; - std::cout << " " << music.getSampleRate() << " samples / sec" << std::endl; - std::cout << " " << music.getChannelCount() << " channels" << std::endl; + LOG(INFO) << filename << ":"; + LOG(INFO) << " " << music.getDuration().asSeconds() << " seconds"; + LOG(INFO) << " " << music.getSampleRate() << " samples / sec"; + LOG(INFO) << " " << music.getChannelCount() << " channels"; // Play it music.play(); @@ -100,10 +97,10 @@ playMusic(const std::string& filename) sf::sleep(sf::milliseconds(100)); // Display the playing position - std::cout << "\rPlaying... " << music.getPlayingOffset().asSeconds() << " sec "; - std::cout << std::flush; + LOG(INFO) << "\rPlaying... " << music.getPlayingOffset().asSeconds() << " sec "; + LOG(INFO) << std::flush; } - std::cout << "\n" << std::endl; + LOG(INFO) << "\n"; #else LOG(INFO) << "playMusic: Audio is supported only on windows!"; #endif @@ -116,14 +113,12 @@ playMusic(const std::string& filename) int main() { - Logger& logger = Logger::getInstance(); - logger.addFileSink("audio-Example", "./"); - logger.addStdoutSink(); + Logger::startLogger(); - #ifndef iMSTK_AUDIO_ENABLED +#ifndef iMSTK_AUDIO_ENABLED LOG(INFO) << "Audio not enabled at build time\n"; return 1; - #endif +#endif LOG(INFO) << "--Testing audio--\n"; diff --git a/Examples/BoneShaving/BoneShavingExample.cpp b/Examples/BoneShaving/BoneShavingExample.cpp index 1c1e80fd08caeb6a862d810a8b744fc9bd98ea59..94ad4f0410a72dfb728627b55a142c3471d18821 100644 --- a/Examples/BoneShaving/BoneShavingExample.cpp +++ b/Examples/BoneShaving/BoneShavingExample.cpp @@ -19,37 +19,36 @@ =========================================================================*/ +#include "imstkLogger.h" #include "imstkMath.h" -#include "imstkTimer.h" -#include "imstkSimulationManager.h" +#include "imstkNew.h" #include "imstkScene.h" +#include "imstkSceneManager.h" +#include "imstkVTKViewer.h" // Objects -#include "imstkSceneObject.h" -#include "imstkLight.h" #include "imstkCamera.h" +#include "imstkCollidingObject.h" +#include "imstkLight.h" // Geometry +#include "imstkMeshIO.h" #include "imstkSphere.h" #include "imstkTetrahedralMesh.h" -#include "imstkSurfaceMesh.h" -#include "imstkMeshIO.h" // Devices and controllers -#include "imstkDeviceTracker.h" -#include "imstkHDAPIDeviceClient.h" -#include "imstkHDAPIDeviceServer.h" +#include "imstkHapticDeviceClient.h" +#include "imstkHapticDeviceManager.h" +#include "imstkKeyboardSceneControl.h" +#include "imstkMouseSceneControl.h" #include "imstkSceneObjectController.h" // Collisions #include "imstkCollisionGraph.h" -#include "imstkInteractionPair.h" -#include "imstkPointSetToSphereCD.h" -#include "imstkVirtualCouplingCH.h" -#include "imstkBoneDrillingCH.h" +#include "imstkObjectInteractionFactory.h" // global variables -const std::string phantomOmni1Name = "Phantom1"; +const std::string phantomOmni1Name = "Default Device"; using namespace imstk; @@ -60,68 +59,79 @@ using namespace imstk; int main() { - // simManager and Scene - auto simManager = std::make_shared<SimulationManager>(); - auto scene = simManager->createNewScene("BoneDrilling"); - - // Add virtual coupling object in the scene. -#ifdef iMSTK_USE_OPENHAPTICS + // Setup logger (write to file and stdout) + Logger::startLogger(); - // Device clients - auto client = std::make_shared<HDAPIDeviceClient>(phantomOmni1Name); + // Create Scene + imstkNew<Scene> scene("BoneDrilling"); // Device Server - auto server = std::make_shared<HDAPIDeviceServer>(); - server->addDeviceClient(client); - simManager->addModule(server); - - // Device tracker - auto deviceTracker = std::make_shared<DeviceTracker>(client); + imstkNew<HapticDeviceManager> server; + std::shared_ptr<HapticDeviceClient> client = server->makeDeviceClient(phantomOmni1Name); // Create bone scene object // Load the mesh - auto tetMesh = MeshIO::read(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg"); + auto tetMesh = MeshIO::read<TetrahedralMesh>(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg"); if (!tetMesh) { LOG(FATAL) << "Could not read mesh from file."; return 1; } - auto bone = std::make_shared<CollidingObject>("Bone"); + imstkNew<CollidingObject> bone("Bone"); bone->setCollidingGeometry(tetMesh); bone->setVisualGeometry(tetMesh); scene->addSceneObject(bone); // Create a virtual coupling object: Drill - auto drillVisualGeom = std::make_shared<Sphere>(); - drillVisualGeom->setRadius(3.); - auto drillCollidingGeom = std::make_shared<Sphere>(); - drillCollidingGeom->setRadius(3.); - auto drill = std::make_shared<CollidingObject>("Drill"); - drill->setCollidingGeometry(drillCollidingGeom); - drill->setVisualGeometry(drillVisualGeom); + imstkNew<Sphere> drillGeom(Vec3d(0.0, 0.0, 0.0), 3.0); + imstkNew<CollidingObject> drill("Drill"); + drill->setCollidingGeometry(drillGeom); + drill->setVisualGeometry(drillGeom); scene->addSceneObject(drill); // Create and add virtual coupling object controller in the scene - auto objController = std::make_shared<SceneObjectController>(drill, deviceTracker); - scene->addObjectController(objController); + imstkNew<SceneObjectController> controller(drill, client); + scene->addController(controller); // Add interaction scene->getCollisionGraph()->addInteraction(makeObjectInteractionPair(bone, drill, - InteractionType::FemObjToCollidingObjBoneDrilling, CollisionDetection::Type::PointSetToSphere)); - -#endif + InteractionType::CollidingObjToCollidingObjBoneDrilling, CollisionDetection::Type::PointSetToSphere)); // Light - auto light = std::make_shared<DirectionalLight>("light"); - light->setFocalPoint(Vec3d(5, -8, -5)); - light->setIntensity(1); + imstkNew<DirectionalLight> light("light"); + light->setFocalPoint(Vec3d(5.0, -8.0, -5.0)); + light->setIntensity(1.0); scene->addLight(light); - //Run - auto cam = scene->getCamera(); - cam->setPosition(Vec3d(0, 0, 15)); + scene->getActiveCamera()->setPosition(Vec3d(0.0, 3.0, 25.0)); - simManager->setActiveScene(scene); - simManager->start(); + //Run the simulation + { + // Setup a viewer to render in its own thread + imstkNew<VTKViewer> viewer("Viewer 1"); + viewer->setActiveScene(scene); + + // Setup a scene manager to advance the scene in its own thread + imstkNew<SceneManager> sceneManager("Scene Manager 1"); + sceneManager->setActiveScene(scene); + viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer + viewer->addChildThread(server); // Server starts/stops with viewer + + // Add mouse and keyboard controls to the viewer + { + imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice()); + mouseControl->setSceneManager(sceneManager); + viewer->addControl(mouseControl); + + imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice()); + keyControl->setSceneManager(sceneManager); + keyControl->setViewer(viewer); + viewer->addControl(keyControl); + } + + // Start viewer running, scene as paused + sceneManager->requestStatus(ThreadStatus::Paused); + viewer->start(); + } return 0; } diff --git a/Examples/CameraController/CameraControllerExample.cpp b/Examples/CameraController/CameraControllerExample.cpp index 8106d64527983b00f6e2bf9617dbae1733f6522b..5cb6ef3b6424a821f5c229d0ebc9bd9ecc889444 100644 --- a/Examples/CameraController/CameraControllerExample.cpp +++ b/Examples/CameraController/CameraControllerExample.cpp @@ -19,22 +19,24 @@ =========================================================================*/ -#include "imstkSimulationManager.h" -#include "imstkSceneObject.h" -#include "imstkLight.h" #include "imstkCamera.h" -#include "imstkMeshIO.h" -#include "imstkScene.h" - -// Devices and controllers -#include "imstkHDAPIDeviceClient.h" -#include "imstkHDAPIDeviceServer.h" #include "imstkCameraController.h" -#include "imstkCollisionGraph.h" - +#include "imstkHapticDeviceClient.h" +#include "imstkHapticDeviceManager.h" +#include "imstkKeyboardSceneControl.h" +#include "imstkLight.h" +#include "imstkLogger.h" +#include "imstkMeshIO.h" +#include "imstkMouseSceneControl.h" +#include "imstkNew.h" +#include "imstkPlane.h" #include "imstkScene.h" +#include "imstkSceneManager.h" +#include "imstkSceneObject.h" +#include "imstkSurfaceMesh.h" +#include "imstkVTKViewer.h" -const std::string phantomOmni1Name = "Phantom1"; +const std::string phantomOmni1Name = "Default Device"; using namespace imstk; @@ -45,58 +47,72 @@ using namespace imstk; int main() { - #ifndef iMSTK_USE_OPENHAPTICS - std::cout << "Audio not enabled at build time" << std::endl; - return 1; - #endif - - // Create simManager and Scene - auto simManager = std::make_shared<SimulationManager>(); - auto scene = simManager->createNewScene("CameraController"); + // Setup logger (write to file and stdout) + Logger::startLogger(); -#ifdef iMSTK_USE_OPENHAPTICS - - auto client = std::make_shared<HDAPIDeviceClient>(phantomOmni1Name); + // Create Scene + imstkNew<Scene> scene("CameraController"); // Device Server - auto server = std::make_shared<HDAPIDeviceServer>(); - server->addDeviceClient(client); - simManager->addModule(server); -#else - LOG(WARNING) << "Phantom device option not enabled during build!"; -#endif + imstkNew<HapticDeviceManager> server; + std::shared_ptr<HapticDeviceClient> client = server->makeDeviceClient(phantomOmni1Name); // Load Mesh - auto mesh = MeshIO::read(iMSTK_DATA_ROOT "/asianDragon/asianDragon.obj"); - auto meshObject = std::make_shared<VisualObject>("meshObject"); + auto mesh = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/asianDragon/asianDragon.obj"); + imstkNew<VisualObject> meshObject("meshObject"); meshObject->setVisualGeometry(mesh); scene->addSceneObject(meshObject); - // Update Camera position - auto camera = scene->getCamera(); - camera->setPosition(Vec3d(0, 0, 10)); + imstkNew<VisualObject> planeObject("Plane"); + imstkNew<Plane> plane(Vec3d(0.0, -2.0, 0.0)); + plane->setWidth(1000.0); + planeObject->setVisualGeometry(plane); + scene->addSceneObject(planeObject); -#ifdef iMSTK_USE_OPENHAPTICS - - auto camController = std::make_shared<CameraController>(camera, client); + // Update Camera position + scene->getActiveCamera()->setPosition(Vec3d(0.0, 0.0, 10.0)); + imstkNew<CameraController> camController(scene->getActiveCamera(), client); //camController->setTranslationScaling(100); //LOG(INFO) << camController->getTranslationOffset(); // should be the same than initial cam position - camController->setInversionFlags(CameraController::InvertFlag::rotY | - CameraController::InvertFlag::rotZ); - - scene->addCameraController(camController); -#endif + scene->addController(camController); // Light - auto light = std::make_shared<DirectionalLight>("light"); - light->setFocalPoint(Vec3d(5, -8, -5)); - light->setIntensity(1); + imstkNew<DirectionalLight> light("light"); + light->setFocalPoint(Vec3d(5.0, -8.0, -5.0)); + light->setIntensity(1.0); scene->addLight(light); - // Run - simManager->setActiveScene(scene); - simManager->start(SimulationStatus::Paused); + //Run the simulation + { + // Setup a viewer to render in its own thread + imstkNew<VTKViewer> viewer("Viewer 1"); + viewer->setActiveScene(scene); + + // Setup a scene manager to advance the scene in its own thread + imstkNew<SceneManager> sceneManager("Scene Manager 1"); + sceneManager->setActiveScene(scene); + viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer + viewer->addChildThread(server); + + // attach the camera controller to the viewer + viewer->addControl(camController); + + // Add mouse and keyboard controls to the viewer + { + imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice()); + mouseControl->setSceneManager(sceneManager); + viewer->addControl(mouseControl); + + imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice()); + keyControl->setSceneManager(sceneManager); + keyControl->setViewer(viewer); + viewer->addControl(keyControl); + } + + // Start viewer and its children + viewer->start(); + } return 0; } diff --git a/Examples/CollisionDetection/Box.cpp b/Examples/CollisionDetection/Box.cpp index 9c428fd83d9e961f6629048360ef024e8f680812..bf4d1eb37e66116134e93fa5c342aba25ba356a6 100644 --- a/Examples/CollisionDetection/Box.cpp +++ b/Examples/CollisionDetection/Box.cpp @@ -22,6 +22,7 @@ #include "imstkMath.h" #include <array> + using namespace imstk; std::pair<StdVectorOfVec3d, std::vector<std::array<size_t, 3>>> diff --git a/Examples/CollisionDetection/BunnyMesh.cpp b/Examples/CollisionDetection/BunnyMesh.cpp index 34ae07934852d15b2cb1c2e36f379fae34fd4c69..417538ef5baaaeb494c3a0daed1fc1f31086fdc9 100644 --- a/Examples/CollisionDetection/BunnyMesh.cpp +++ b/Examples/CollisionDetection/BunnyMesh.cpp @@ -23,6 +23,7 @@ #include "imstkLogger.h" #include <array> + using namespace imstk; std::pair<StdVectorOfVec3d, std::vector<std::array<size_t, 3>>> diff --git a/Examples/CollisionDetection/ManualCDWithOctree/ManualCDWithOctreeExample.cpp b/Examples/CollisionDetection/ManualCDWithOctree/ManualCDWithOctreeExample.cpp index dfd7fca130b89d5d634e3854dd9e6c6d753cdf6a..40e28c6b2214b7f7eff8993168152ba70077e1c3 100644 --- a/Examples/CollisionDetection/ManualCDWithOctree/ManualCDWithOctreeExample.cpp +++ b/Examples/CollisionDetection/ManualCDWithOctree/ManualCDWithOctreeExample.cpp @@ -19,29 +19,26 @@ =========================================================================*/ -#include "imstkSimulationManager.h" -#include "imstkLight.h" -#include "imstkSceneObject.h" -#include "imstkDebugRenderGeometry.h" -#include "imstkAPIUtilities.h" -#include "imstkVTKViewer.h" -#include "imstkTimer.h" -#include "imstkVTKTextStatusManager.h" -#include "imstkCollisionData.h" #include "imstkCamera.h" -#include "imstkDebugRenderGeometry.h" #include "imstkCollidingObject.h" +#include "imstkCollisionData.h" +#include "imstkDebugRenderGeometry.h" +#include "imstkKeyboardDeviceClient.h" +#include "imstkKeyboardSceneControl.h" +#include "imstkLight.h" +#include "imstkMouseSceneControl.h" +#include "imstkNew.h" +#include "imstkOctreeBasedCD.h" +#include "imstkRenderMaterial.h" +#include "imstkScene.h" #include "imstkSceneManager.h" #include "imstkSurfaceMesh.h" -#include "imstkScene.h" +#include "imstkTimer.h" +#include "imstkVisualModel.h" +#include "imstkVTKRenderDelegate.h" #include "imstkVTKRenderer.h" - -// This is for collision detection between geometries -#include "imstkOctreeBasedCD.h" - -#include <map> -#include <thread> -#include <chrono> +#include "imstkVTKTextStatusManager.h" +#include "imstkVTKViewer.h" using namespace imstk; @@ -68,19 +65,18 @@ static std::pair<StdVectorOfVec3d, std::vector<std::array<size_t, 3>>> g_BunnyDa /// \brief Read a mesh, create a visual scene object and add to the scene /// std::shared_ptr<CollidingObject> -createMeshObject(const std::shared_ptr<imstk::Scene>& scene, - const std::string& objectName, - Color color) +createMeshObject(const std::string& objectName, + Color color) { // Create a surface mesh - auto meshObj = std::make_shared<SurfaceMesh>(objectName); + imstkNew<SurfaceMesh> meshObj(objectName); meshObj->initialize(MESH_DATA.first, MESH_DATA.second); // Create a visiual model - auto visualModel = std::make_shared<VisualModel>(meshObj); - auto material = std::make_shared<RenderMaterial>(); + imstkNew<VisualModel> visualModel(meshObj.get()); + imstkNew<RenderMaterial> material; material->setEdgeColor(color); // Wireframe color - material->setLineWidth(2); + material->setLineWidth(2.0); if (meshObj->getNumTriangles() > 100) { material->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface); @@ -92,12 +88,10 @@ createMeshObject(const std::shared_ptr<imstk::Scene>& scene, visualModel->setRenderMaterial(material); // Create object and add to scene - auto meshSceneObject = std::make_shared<CollidingObject>(objectName); + imstkNew<CollidingObject> meshSceneObject(objectName); meshSceneObject->setCollidingGeometry(meshObj); meshSceneObject->addVisualModel(visualModel); - scene->addSceneObject(meshSceneObject); - LOG_IF(FATAL, (!meshSceneObject)) << "ERROR: Unable to create scene object"; return meshSceneObject; } @@ -107,16 +101,16 @@ createMeshObject(const std::shared_ptr<imstk::Scene>& scene, std::shared_ptr<DebugRenderGeometry> addPointsDebugRendering(const std::shared_ptr<Scene>& scene) { - auto debugPoints = std::make_shared<DebugRenderPoints>("Debug Points"); - auto material = std::make_shared<RenderMaterial>(); + imstkNew<DebugRenderPoints> debugPoints("Debug Points"); + imstkNew<RenderMaterial> material; material->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface); material->setVertexColor(Color::Yellow); - material->setPointSize(8.); + material->setPointSize(8.0); - auto dbgViz = std::make_shared<VisualModel>(debugPoints, material); + imstkNew<VisualModel> dbgViz(debugPoints.get(), material); scene->addDebugVisualModel(dbgViz); - return std::dynamic_pointer_cast<DebugRenderGeometry>(debugPoints); + return debugPoints; } /// @@ -125,16 +119,16 @@ addPointsDebugRendering(const std::shared_ptr<Scene>& scene) std::shared_ptr<DebugRenderGeometry> addVTConnectingLinesDebugRendering(const std::shared_ptr<Scene>& scene) { - auto debugLines = std::make_shared<DebugRenderLines>("Debug Connecting VT Lines"); - auto material = std::make_shared<RenderMaterial>(); + imstkNew<DebugRenderLines> debugLines("Debug Connecting VT Lines"); + imstkNew<RenderMaterial> material; material->setBackFaceCulling(false); material->setEdgeColor(Color::Green); material->setLineWidth(4.0); - auto dbgViz = std::make_shared<VisualModel>(debugLines, material); + imstkNew<VisualModel> dbgViz(debugLines.get(), material); scene->addDebugVisualModel(dbgViz); - return std::dynamic_pointer_cast<DebugRenderGeometry>(debugLines); + return debugLines; } /// @@ -143,16 +137,16 @@ addVTConnectingLinesDebugRendering(const std::shared_ptr<Scene>& scene) std::shared_ptr<DebugRenderGeometry> addEEConnectingLinesDebugRendering(const std::shared_ptr<Scene>& scene) { - auto debugLines = std::make_shared<DebugRenderLines>("Debug Connecting EE Lines"); - auto material = std::make_shared<RenderMaterial>(); + imstkNew<DebugRenderLines> debugLines("Debug Connecting EE Lines"); + imstkNew<RenderMaterial> material; material->setBackFaceCulling(false); material->setEdgeColor(Color::Red); material->setLineWidth(4.0); - auto dbgViz = std::make_shared<VisualModel>(debugLines, material); + imstkNew<VisualModel> dbgViz(debugLines.get(), material); scene->addDebugVisualModel(dbgViz); - return std::dynamic_pointer_cast<DebugRenderGeometry>(debugLines); + return debugLines; } /// @@ -161,16 +155,16 @@ addEEConnectingLinesDebugRendering(const std::shared_ptr<Scene>& scene) std::shared_ptr<DebugRenderGeometry> addHighlightedLinesDebugRendering(const std::shared_ptr<Scene>& scene) { - auto debugLines = std::make_shared<DebugRenderLines>("Debug Highlighted Lines"); - auto material = std::make_shared<RenderMaterial>(); + imstkNew<DebugRenderLines> debugLines("Debug Highlighted Lines"); + imstkNew<RenderMaterial> material; material->setBackFaceCulling(false); material->setEdgeColor(Color::Orange); material->setLineWidth(8.0); - auto dbgViz = std::make_shared<VisualModel>(debugLines, material); + imstkNew<VisualModel> dbgViz(debugLines.get(), material); scene->addDebugVisualModel(dbgViz); - return std::dynamic_pointer_cast<DebugRenderGeometry>(debugLines); + return debugLines; } /// @@ -202,23 +196,19 @@ getRandomColor() int main() { - // simManager and Scene - auto simManager = std::make_shared<SimulationManager>(); - auto scene = simManager->createNewScene("Collision Test"); + Logger::startLogger(); - // Configure the VTKViewer - std::shared_ptr<VTKViewer> viewer = std::make_shared<VTKViewer>(simManager.get(), false); + imstkNew<Scene> scene("Collision Test"); + + // Setup a viewer to render in its own thread + imstkNew<VTKViewer> viewer("Viewer"); + viewer->setActiveScene(scene); viewer->setWindowTitle("Collision Test"); - viewer->getVtkRenderWindow()->SetSize(1920, 1080); + viewer->setSize(1920, 1080); auto statusManager = viewer->getTextStatusManager(); - statusManager->setStatusFontSize(VTKTextStatusManager::Custom, 25); - statusManager->setStatusFontColor(VTKTextStatusManager::Custom, Color::Orange); - simManager->setViewer(viewer); - simManager->setActiveScene(scene); // Viewer has depedence on scene - - // Get VTK Renderer - auto renderer = std::dynamic_pointer_cast<VTKRenderer>(viewer->getActiveRenderer()); - LOG_IF(FATAL, (!renderer)) << "Invalid renderer: Only VTKRenderer is supported for debug rendering"; + statusManager->setStatusFontSize(VTKTextStatusManager::StatusType::Custom, 25); + statusManager->setStatusFontColor(VTKTextStatusManager::StatusType::Custom, Color::Orange); + std::shared_ptr<VTKRenderer> ren = std::dynamic_pointer_cast<VTKRenderer>(viewer->getActiveRenderer()); // srand(123456); // Deterministic random generation, for random colors srand(static_cast<unsigned int>(time(nullptr))); @@ -227,7 +217,8 @@ main() std::vector<std::shared_ptr<SurfaceMesh>> triMeshes; for (unsigned int i = 0; i < NUM_MESHES; ++i) { - const auto sceneObj = createMeshObject(scene, "Mesh-" + std::to_string(triMeshes.size()), getRandomColor()); + std::shared_ptr<CollidingObject> sceneObj = createMeshObject("Mesh-" + std::to_string(triMeshes.size()), getRandomColor()); + scene->addSceneObject(sceneObj); triMeshes.push_back(std::dynamic_pointer_cast<SurfaceMesh>(sceneObj->getVisualGeometry())); } @@ -245,7 +236,7 @@ main() timer.start(); // Create an octree - OctreeBasedCD octreeCD(Vec3d(0, 0, 0), 100.0, 0.125, 1); + OctreeBasedCD octreeCD(Vec3d(0.0, 0.0, 0.0), 100.0, 0.125, 1); for (const auto& obj: triMeshes) { @@ -263,7 +254,7 @@ main() { if (i != j) { - octreeCD.addCollisionPair(triMeshes[i], triMeshes[j], CollisionDetection::Type::SurfaceMeshToSurfaceMesh); + octreeCD.addCollisionPair(triMeshes[i], triMeshes[j], CollisionDetection::Type::SurfaceMeshToSurfaceMesh, std::make_shared<CollisionData>()); } } } @@ -278,11 +269,11 @@ main() #ifdef DEBUG_RENDER_OCTREE const auto debugOctree = octreeCD.getDebugGeometry(8, false); - const auto matDbgViz = std::make_shared<RenderMaterial>(); + imstkNew<RenderMaterial> matDbgViz; matDbgViz->setDisplayMode(RenderMaterial::DisplayMode::Wireframe); matDbgViz->setEdgeColor(Color::Green); matDbgViz->setLineWidth(1.0); - auto octreeVizDbgModel = std::make_shared<VisualModel>(debugOctree, matDbgViz); + imstkNew<VisualModel> octreeVizDbgModel(debugOctree, matDbgViz); scene->addDebugVisualModel(octreeVizDbgModel); #endif @@ -318,179 +309,197 @@ main() dirs[i][2] = -std::sin(rotation) * t; } - auto updateFunc = - [&](Module*) { - for (size_t i = 0; i < triMeshes.size(); ++i) - { - triMeshes[i]->translate(dirs[i][0], dirs[i][1], dirs[i][2], Geometry::TransformType::ApplyToData); - centers[i] += dirs[i]; - - // Trick to force update geometry postUpdateTransform - const auto positions = triMeshes[i]->getVertexPositions(); - (void)positions; - } - - Vec3d lowerCorners, upperCorner; - ParallelUtils::findAABB(centers, lowerCorners, upperCorner); - if ((lowerCorners - upperCorner).norm() > 70.0) - { - for (auto& dir : dirs) - { - dir = -dir; - } - } - - StopWatch timer; - - // Update octree - timer.start(); - octreeCD.update(); - const auto updateTime = timer.getTimeElapsed(); + auto updateFunc = [&](Event*) + { + for (size_t i = 0; i < triMeshes.size(); ++i) + { + triMeshes[i]->translate(dirs[i][0], dirs[i][1], dirs[i][2], Geometry::TransformType::ApplyToData); + centers[i] += dirs[i]; + + // Trick to force update geometry postUpdateTransform + const auto positions = triMeshes[i]->getVertexPositions(); + (void)positions; + } + + Vec3d lowerCorners, upperCorner; + ParallelUtils::findAABB(centers, lowerCorners, upperCorner); + if ((lowerCorners - upperCorner).norm() > 70.0) + { + for (auto& dir : dirs) + { + dir = -dir; + } + } + + StopWatch timer; + + // Update octree + timer.start(); + octreeCD.update(); + const auto updateTime = timer.getTimeElapsed(); #ifdef DEBUG_RENDER_OCTREE - octreeCD.updateDebugGeometry(); + octreeCD.updateDebugGeometry(); #endif - // Detect collision - timer.start(); - octreeCD.detectCollision(); - const auto CDTime = timer.getTimeElapsed(); - - const auto numActiveNodes = octreeCD.getNumActiveNodes(); - const auto numTotalNodes = octreeCD.getNumAllocatedNodes(); - const auto numPrimitives = octreeCD.getPrimitiveCount(OctreePrimitiveType::Point) + - octreeCD.getPrimitiveCount(OctreePrimitiveType::Triangle) + - octreeCD.getPrimitiveCount(OctreePrimitiveType::AnalyticalGeometry); - const auto maxNumPrimitivesInTree = octreeCD.getMaxNumPrimitivesInNodes(); - - // Clear collision debug rendering - debugPoints->clear(); - debugVTConnectingLines->clear(); - debugEEConnectingLines->clear(); - debugHighlightedLines->clear(); - - size_t numVTCollisions = 0; - size_t numEECollisions = 0; - for (const auto& geoPair : octreeCD.getCollidingGeometryPairs()) - { - const auto& colData = octreeCD.getCollisionPairData(geoPair.first->getGlobalIndex(), + // Detect collision + timer.start(); + octreeCD.detectCollision(); + const auto CDTime = timer.getTimeElapsed(); + + const auto numActiveNodes = octreeCD.getNumActiveNodes(); + const auto numTotalNodes = octreeCD.getNumAllocatedNodes(); + const auto numPrimitives = octreeCD.getPrimitiveCount(OctreePrimitiveType::Point) + + octreeCD.getPrimitiveCount(OctreePrimitiveType::Triangle) + + octreeCD.getPrimitiveCount(OctreePrimitiveType::AnalyticalGeometry); + const auto maxNumPrimitivesInTree = octreeCD.getMaxNumPrimitivesInNodes(); + + // Clear collision debug rendering + debugPoints->clear(); + debugVTConnectingLines->clear(); + debugEEConnectingLines->clear(); + debugHighlightedLines->clear(); + + size_t numVTCollisions = 0; + size_t numEECollisions = 0; + for (const auto& geoPair : octreeCD.getCollidingGeometryPairs()) + { + const auto& colData = octreeCD.getCollisionPairData(geoPair.first->getGlobalIndex(), geoPair.second->getGlobalIndex()); - if (colData->VTColData.getSize()) - { - numVTCollisions += colData->VTColData.getSize(); - const auto mesh1 = static_cast<SurfaceMesh*>(geoPair.first); - const auto mesh2 = static_cast<SurfaceMesh*>(geoPair.second); - for (size_t i = 0; i < colData->VTColData.getSize(); ++i) - { - const auto tv = colData->VTColData[i]; - const auto v = mesh1->getVertexPosition(tv.vertexIdx); - debugPoints->appendVertex(v); - - const auto face = mesh2->getTrianglesVertices()[tv.triIdx]; - const auto tv0 = mesh2->getVertexPosition(face[0]); - const auto tv1 = mesh2->getVertexPosition(face[1]); - const auto tv2 = mesh2->getVertexPosition(face[2]); - - debugHighlightedLines->appendVertex(tv0); - debugHighlightedLines->appendVertex(tv1); - debugHighlightedLines->appendVertex(tv1); - debugHighlightedLines->appendVertex(tv2); - debugHighlightedLines->appendVertex(tv2); - debugHighlightedLines->appendVertex(tv0); - - debugVTConnectingLines->appendVertex(v); - debugVTConnectingLines->appendVertex((tv0 + tv1 + tv2) / 3.0); - } - } + if (colData->VTColData.getSize()) + { + numVTCollisions += colData->VTColData.getSize(); + const auto mesh1 = static_cast<SurfaceMesh*>(geoPair.first); + const auto mesh2 = static_cast<SurfaceMesh*>(geoPair.second); + for (size_t i = 0; i < colData->VTColData.getSize(); ++i) + { + const auto tv = colData->VTColData[i]; + const auto v = mesh1->getVertexPosition(tv.vertexIdx); + debugPoints->appendVertex(v); + + const auto face = mesh2->getTrianglesVertices()[tv.triIdx]; + const auto tv0 = mesh2->getVertexPosition(face[0]); + const auto tv1 = mesh2->getVertexPosition(face[1]); + const auto tv2 = mesh2->getVertexPosition(face[2]); + + debugHighlightedLines->appendVertex(tv0); + debugHighlightedLines->appendVertex(tv1); + debugHighlightedLines->appendVertex(tv1); + debugHighlightedLines->appendVertex(tv2); + debugHighlightedLines->appendVertex(tv2); + debugHighlightedLines->appendVertex(tv0); + + debugVTConnectingLines->appendVertex(v); + debugVTConnectingLines->appendVertex((tv0 + tv1 + tv2) / 3.0); + } + } + + if (colData->EEColData.getSize()) + { + numEECollisions += colData->EEColData.getSize(); + const auto mesh1 = static_cast<SurfaceMesh*>(geoPair.first); + const auto mesh2 = static_cast<SurfaceMesh*>(geoPair.second); + for (size_t i = 0; i < colData->EEColData.getSize(); ++i) + { + const auto ee = colData->EEColData[i]; + + const auto e0v0 = mesh1->getVertexPosition(ee.edgeIdA.first); + const auto e0v1 = mesh1->getVertexPosition(ee.edgeIdA.second); + const auto e0Center = (e0v0 + e0v1) * 0.5; + debugPoints->appendVertex(e0Center); + + const auto e1v0 = mesh2->getVertexPosition(ee.edgeIdB.first); + const auto e1v1 = mesh2->getVertexPosition(ee.edgeIdB.second); + const auto e1Center = (e1v0 + e1v1) * 0.5; + debugPoints->appendVertex(e1Center); + + debugHighlightedLines->appendVertex(e0v0); + debugHighlightedLines->appendVertex(e0v1); + debugHighlightedLines->appendVertex(e1v0); + debugHighlightedLines->appendVertex(e1v1); + + debugEEConnectingLines->appendVertex(e0Center); + debugEEConnectingLines->appendVertex(e1Center); + } + } + } + + debugPoints->setDataModified(true); + debugVTConnectingLines->setDataModified(true); + debugEEConnectingLines->setDataModified(true); + debugHighlightedLines->setDataModified(true); + + std::stringstream ss; + ss << "Octree update time: " << updateTime << " ms\n" + << "Active nodes: " << numActiveNodes + << " (" << static_cast<double>(numActiveNodes) / static_cast<double>(numTotalNodes) * 100.0 + << " % usage / total allocated nodes: " << numTotalNodes << ")\n" + << "Num. primitives: " << numPrimitives + << " | Max number of primitives in tree nodes: " << maxNumPrimitivesInTree + << "\nCollision detection time: " << CDTime << " ms" + << "\nNum. collision: " << numVTCollisions << " (VT) | " + << numEECollisions << " (EE)"; + statusManager->setCustomStatus(ss.str()); + + // Update debug rendering data + for (auto& delegate : ren->getDebugRenderDelegates()) + { + delegate->updateDataSource(); + } + + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + }; - if (colData->EEColData.getSize()) - { - numEECollisions += colData->EEColData.getSize(); - const auto mesh1 = static_cast<SurfaceMesh*>(geoPair.first); - const auto mesh2 = static_cast<SurfaceMesh*>(geoPair.second); - for (size_t i = 0; i < colData->EEColData.getSize(); ++i) - { - const auto ee = colData->EEColData[i]; + // Set Camera configuration + scene->getActiveCamera()->setPosition(Vec3d(0.0, 15.0, 50.0)); - const auto e0v0 = mesh1->getVertexPosition(ee.edgeIdA.first); - const auto e0v1 = mesh1->getVertexPosition(ee.edgeIdA.second); - const auto e0Center = (e0v0 + e0v1) * 0.5; - debugPoints->appendVertex(e0Center); + // Light + imstkNew<DirectionalLight> light1("Light1"); + light1->setFocalPoint(Vec3d(-1.0, -1.0, -1.0)); + light1->setIntensity(1.0); + scene->addLight(light1); - const auto e1v0 = mesh2->getVertexPosition(ee.edgeIdB.first); - const auto e1v1 = mesh2->getVertexPosition(ee.edgeIdB.second); - const auto e1Center = (e1v0 + e1v1) * 0.5; - debugPoints->appendVertex(e1Center); + imstkNew<DirectionalLight> light2("Light2"); + light2->setFocalPoint(Vec3d(1.0, -1.0, -1.0)); + light2->setIntensity(1.0); + scene->addLight(light2); - debugHighlightedLines->appendVertex(e0v0); - debugHighlightedLines->appendVertex(e0v1); - debugHighlightedLines->appendVertex(e1v0); - debugHighlightedLines->appendVertex(e1v1); + // Run the simulation + { + // Setup a scene manager to advance the scene in its own thread + imstkNew<SceneManager> sceneManager("Scene Manager"); + sceneManager->setActiveScene(scene); + viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer + connect<Event>(sceneManager, EventType::PostUpdate, updateFunc); - debugEEConnectingLines->appendVertex(e0Center); - debugEEConnectingLines->appendVertex(e1Center); + // Add mouse and keyboard controls to the viewer + { + imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice()); + mouseControl->setSceneManager(sceneManager); + viewer->addControl(mouseControl); + + imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice()); + keyControl->setSceneManager(sceneManager); + keyControl->setViewer(viewer); + viewer->addControl(keyControl); + + // Add an extra control + connect<KeyPressEvent>(viewer->getKeyboardDevice(), EventType::KeyPress, + [&](KeyPressEvent* e) + { + if (e->m_key == 'b' && e->m_keyPressType == KEY_PRESS) + { + for (auto& dir : dirs) + { + dir = -dir; } } - } - - debugPoints->setDataModified(true); - debugVTConnectingLines->setDataModified(true); - debugEEConnectingLines->setDataModified(true); - debugHighlightedLines->setDataModified(true); - - std::stringstream ss; - ss << "Octree update time: " << updateTime << " ms\n" - << "Active nodes: " << numActiveNodes - << " (" << static_cast<double>(numActiveNodes) / static_cast<double>(numTotalNodes) * 100.0 - << " % usage / total allocated nodes: " << numTotalNodes << ")\n" - << "Num. primitives: " << numPrimitives - << " | Max number of primitives in tree nodes: " << maxNumPrimitivesInTree - << "\nCollision detection time: " << CDTime << " ms" - << "\nNum. collision: " << numVTCollisions << " (VT) | " - << numEECollisions << " (EE)"; - statusManager->setCustomStatus(ss.str()); - - // Update debug rendering data - for (auto& delegate : renderer->getDebugRenderDelegates()) - { - delegate->updateDataSource(); - } - - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - }; - simManager->getSceneManager(scene)->setPostUpdateCallback(updateFunc); - - // Press 'b' key to move objects in the reverse directions - viewer->setOnCharFunction('b', - [&](InteractorStyle*) -> bool - { - for (auto& dir : dirs) - { - dir = -dir; + }); } - return true; - }); - // Set Camera configuration - auto cam = scene->getCamera(); - cam->setPosition(Vec3d(0, 15, 50)); - cam->setFocalPoint(Vec3d(0, 0, 0)); - - // Light - { - auto light = std::make_shared<DirectionalLight>("Light 1"); - light->setFocalPoint(Vec3d(-1, -1, -1)); - light->setIntensity(1); - scene->addLight(light); + // Start viewer running, scene as paused + sceneManager->requestStatus(ThreadStatus::Paused); + viewer->start(); } - { - auto light = std::make_shared<DirectionalLight>("Light 2"); - light->setFocalPoint(Vec3d(1, -1, -1)); - light->setIntensity(1); - scene->addLight(light); - } - - // Run - simManager->start(SimulationStatus::Paused); return 0; } diff --git a/Examples/CollisionDetection/Sphere.cpp b/Examples/CollisionDetection/Sphere.cpp index f51842b78010099b998469758090a3b0629efde2..3dcc96683614fcffdb94b879760f9c1d5fa92417 100644 --- a/Examples/CollisionDetection/Sphere.cpp +++ b/Examples/CollisionDetection/Sphere.cpp @@ -22,6 +22,7 @@ #include "imstkMath.h" #include <array> + using namespace imstk; std::pair<StdVectorOfVec3d, std::vector<std::array<size_t, 3>>> diff --git a/Examples/CollisionDetection/Triangle.cpp b/Examples/CollisionDetection/Triangle.cpp index c2c396fdb42256f056df1ea30c4c2e1076d0b62a..75fdd40c84a40b828a578d8fad1cd2850361f76c 100644 --- a/Examples/CollisionDetection/Triangle.cpp +++ b/Examples/CollisionDetection/Triangle.cpp @@ -22,6 +22,7 @@ #include "imstkMath.h" #include <array> + using namespace imstk; std::pair<StdVectorOfVec3d, std::vector<std::array<size_t, 3>>> diff --git a/Examples/CreateEnclosingMesh/CreateEnclosingMesh.cpp b/Examples/CreateEnclosingMesh/CreateEnclosingMesh.cpp index 0fe78bb592a44389ceb61cab79e045de1cb73c01..2eaeef02cc57c46b1fb017cb7ca45538cdf5b96e 100644 --- a/Examples/CreateEnclosingMesh/CreateEnclosingMesh.cpp +++ b/Examples/CreateEnclosingMesh/CreateEnclosingMesh.cpp @@ -19,17 +19,22 @@ =========================================================================*/ -#include "imstkSimulationManager.h" -#include "imstkSceneManager.h" -#include "imstkLight.h" #include "imstkCamera.h" -#include "imstkAPIUtilities.h" -#include "imstkSurfaceMesh.h" -#include "imstkTetrahedralMesh.h" -#include "imstkMeshIO.h" -#include "imstkVTKMeshIO.h" #include "imstkGeometryUtilities.h" +#include "imstkKeyboardSceneControl.h" +#include "imstkLight.h" +#include "imstkLogger.h" +#include "imstkMeshIO.h" +#include "imstkMouseSceneControl.h" +#include "imstkNew.h" +#include "imstkRenderMaterial.h" #include "imstkScene.h" +#include "imstkSceneManager.h" +#include "imstkSceneObject.h" +#include "imstkSurfaceMesh.h" +#include "imstkTetrahedralMesh.h" +#include "imstkVisualModel.h" +#include "imstkVTKViewer.h" using namespace imstk; @@ -38,50 +43,77 @@ const size_t nx = 80 / 2, ny = 40 / 2, nz = 40 / 2; int main() { - // Create simulation manager - auto simManager = std::make_shared<SimulationManager>(); + // Setup logger (write to file and stdout) + Logger::startLogger(); // Create a sample scene - auto scene = simManager->createNewScene("renderMesh"); - scene->getCamera()->setPosition(0, 2.0, 15.0); - - // add scene object for surface object - auto surfaceObject = std::make_shared<VisualObject>("SurfaceObj"); - - auto surfMesh = std::dynamic_pointer_cast<SurfaceMesh>(MeshIO::read(iMSTK_DATA_ROOT "/asianDragon/asianDragon.obj")); - - // configure and add the render model to the scene object - auto material = std::make_shared<RenderMaterial>(); - material->setDisplayMode(RenderMaterial::DisplayMode::Surface); - material->setColor(Color::LightGray); - auto surfMeshModel = std::make_shared<VisualModel>(surfMesh); - surfMeshModel->setRenderMaterial(material); - surfaceObject->addVisualModel(surfMeshModel); - - // add the scene object to the scene - scene->addSceneObject(surfaceObject); - - auto tetMesh = GeometryUtils::createTetrahedralMeshCover(surfMesh, nx, ny, nz); - - // add scene object for surface object - auto volObject = std::make_shared<VisualObject>("VolObj"); - auto tetMaterial = std::make_shared<RenderMaterial>(); - tetMaterial->setDisplayMode(RenderMaterial::DisplayMode::Wireframe); - tetMaterial->setEdgeColor(Color::Teal); - tetMaterial->setPointSize(7.); - tetMaterial->setLineWidth(3.); - auto tetVizModel = std::make_shared<VisualModel>(tetMesh, tetMaterial); - volObject->addVisualModel(tetVizModel); - - scene->addSceneObject(volObject); - - // Light - auto light = std::make_shared<DirectionalLight>("light"); - light->setFocalPoint(Vec3d(5, -8, -5)); - light->setIntensity(1); - scene->addLight(light); - - simManager->setActiveScene(scene); - simManager->getViewer()->setBackgroundColors(Vec3d(0.3285, 0.3285, 0.6525), Vec3d(0.13836, 0.13836, 0.2748), true); - simManager->start(); + imstkNew<Scene> scene("renderMesh"); + { + scene->getActiveCamera()->setPosition(0.0, 2.0, 15.0); + + // add scene object for surface object + imstkNew<VisualObject> surfObj("SurfaceObject"); + + auto surfMesh = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/asianDragon/asianDragon.obj"); + + // configure and add the render model to the scene object + imstkNew<RenderMaterial> material; + material->setDisplayMode(RenderMaterial::DisplayMode::Surface); + material->setColor(Color::LightGray); + imstkNew<VisualModel> visualModel(surfMesh); + visualModel->setRenderMaterial(material); + surfObj->addVisualModel(visualModel); + + // add the scene object to the scene + scene->addSceneObject(surfObj); + + std::shared_ptr<TetrahedralMesh> tetMesh = + GeometryUtils::createTetrahedralMeshCover(surfMesh, nx, ny, nz); + + // add scene object for surface object + imstkNew<VisualObject> volObject("VolObj"); + imstkNew<RenderMaterial> tetMaterial; + tetMaterial->setDisplayMode(RenderMaterial::DisplayMode::Wireframe); + tetMaterial->setEdgeColor(Color::Teal); + tetMaterial->setPointSize(7.0); + tetMaterial->setLineWidth(3.0); + imstkNew<VisualModel> tetVisualModel(tetMesh, tetMaterial); + volObject->addVisualModel(tetVisualModel); + + scene->addSceneObject(volObject); + + // Light + imstkNew<DirectionalLight> light("light"); + light->setFocalPoint(Vec3d(5.0, -8.0, -5.0)); + light->setIntensity(1); + scene->addLight(light); + } + + // Run the simulation + { + // Setup a viewer to render in its own thread + imstkNew<VTKViewer> viewer("Viewer"); + viewer->setActiveScene(scene); + viewer->setBackgroundColors(Vec3d(0.3285, 0.3285, 0.6525), Vec3d(0.13836, 0.13836, 0.2748), true); + + // Setup a scene manager to advance the scene in its own thread + imstkNew<SceneManager> sceneManager("Scene Manager"); + sceneManager->setActiveScene(scene); + viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer + + // Add mouse and keyboard controls to the viewer + { + imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice()); + mouseControl->setSceneManager(sceneManager); + viewer->addControl(mouseControl); + + imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice()); + keyControl->setSceneManager(sceneManager); + keyControl->setViewer(viewer); + viewer->addControl(keyControl); + } + + // Start viewer running, scene as paused + viewer->start(); + } } diff --git a/Examples/DebugRendering/DebugRenderingExample.cpp b/Examples/DebugRendering/DebugRenderingExample.cpp index 7e8ab3551d168247e5c53b7f369eeaf4a96ed163..f91fcb295b624f4c3afe166726cf9a17bf8ebae9 100644 --- a/Examples/DebugRendering/DebugRenderingExample.cpp +++ b/Examples/DebugRendering/DebugRenderingExample.cpp @@ -19,32 +19,33 @@ =========================================================================*/ -#include "imstkSimulationManager.h" -#include "imstkSceneObject.h" -#include "imstkLight.h" #include "imstkCamera.h" -#include "imstkSceneManager.h" #include "imstkDebugRenderGeometry.h" -#include "imstkAPIUtilities.h" -#include "imstkVTKViewer.h" +#include "imstkKeyboardSceneControl.h" +#include "imstkLight.h" +#include "imstkLogger.h" +#include "imstkMouseSceneControl.h" +#include "imstkNew.h" +#include "imstkRenderMaterial.h" +#include "imstkScene.h" +#include "imstkSceneManager.h" +#include "imstkVisualModel.h" +#include "imstkVTKRenderDelegate.h" #include "imstkVTKRenderer.h" #include "imstkVTKTextStatusManager.h" -#include "imstkScene.h" - -#include <thread> -#include <chrono> +#include "imstkVTKViewer.h" using namespace imstk; std::shared_ptr<DebugRenderPoints> addPointsDebugRendering(const std::shared_ptr<Scene>& scene) { - auto debugPoints = std::make_shared<DebugRenderPoints>("Debug Points"); - auto material = std::make_shared<RenderMaterial>(); + imstkNew<DebugRenderPoints> debugPoints("Debug Points"); + imstkNew<RenderMaterial> material; material->setDisplayMode(RenderMaterial::DisplayMode::Points); material->setPointSize(6.); - auto vizModel = std::make_shared<VisualModel>(debugPoints, material); - scene->addDebugVisualModel(vizModel); + imstkNew<VisualModel> visualModel(debugPoints.get(), material); + scene->addDebugVisualModel(visualModel); return debugPoints; } @@ -52,14 +53,14 @@ addPointsDebugRendering(const std::shared_ptr<Scene>& scene) std::shared_ptr<DebugRenderLines> addLinesDebugRendering(const std::shared_ptr<Scene>& scene) { - auto debugLines = std::make_shared<DebugRenderLines>("Debug Lines"); - auto material = std::make_shared<RenderMaterial>(); + imstkNew<DebugRenderLines> debugLines("Debug Lines"); + imstkNew<RenderMaterial> material; material->setDisplayMode(RenderMaterial::DisplayMode::Wireframe); //material->setBackFaceCulling(false); material->setEdgeColor(Color::Green); material->setLineWidth(4.0); - auto vizModel = std::make_shared<VisualModel>(debugLines, material); - scene->addDebugVisualModel(vizModel); + imstkNew<VisualModel> visualModel(debugLines.get(), material); + scene->addDebugVisualModel(visualModel); return debugLines; } @@ -67,19 +68,19 @@ addLinesDebugRendering(const std::shared_ptr<Scene>& scene) std::shared_ptr<DebugRenderTriangles> addTrianglesDebugRendering(const std::shared_ptr<Scene>& scene) { - auto debugTriangles = std::make_shared<DebugRenderTriangles>("Debug Triangles"); - auto material = std::make_shared<RenderMaterial>(); + imstkNew<DebugRenderTriangles> debugTriangles("Debug Triangles"); + imstkNew<RenderMaterial> material; material->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface); material->setBackFaceCulling(false); material->setColor(Color::Red); - auto vizModel = std::make_shared<VisualModel>(debugTriangles, material); - scene->addDebugVisualModel(vizModel); + imstkNew<VisualModel> visualModel(debugTriangles.get(), material); + scene->addDebugVisualModel(visualModel); return debugTriangles; } Vec3d -getRandomPositions(double radius) +getRandomPositions(const double radius) { return radius * Vec3d(2.0 * static_cast<double>(rand()) / static_cast<double>(RAND_MAX) - 1.0, 2.0 * static_cast<double>(rand()) / static_cast<double>(RAND_MAX) - 1.0, @@ -92,20 +93,21 @@ getRandomPositions(double radius) int main() { - // simManager and Scene - auto simManager = std::make_shared<SimulationManager>(); - auto scene = simManager->createNewScene("Debug rendering example"); + // Setup logger (write to file and stdout) + Logger::startLogger(); + + // Create a scene + imstkNew<Scene> scene("Debug rendering example"); - // Get the VTKViewer - std::shared_ptr<VTKViewer> viewer = std::make_shared<VTKViewer>(simManager.get(), false); + // Setup a viewer to render in its own thread + imstkNew<VTKViewer> viewer("Viewer"); + viewer->setActiveScene(scene); viewer->setWindowTitle("Debug Rendering"); - viewer->getVtkRenderWindow()->SetSize(1920, 1080); - simManager->setViewer(viewer); - simManager->setActiveScene(scene); // Viewer has depedence on scene + viewer->setSize(1920, 1080); auto statusManager = viewer->getTextStatusManager(); - statusManager->setStatusFontSize(VTKTextStatusManager::Custom, 30); - statusManager->setStatusFontColor(VTKTextStatusManager::Custom, Color::Orange); + statusManager->setStatusFontSize(VTKTextStatusManager::StatusType::Custom, 30); + statusManager->setStatusFontColor(VTKTextStatusManager::StatusType::Custom, Color::Orange); // Get VTK Renderer auto renderer = std::dynamic_pointer_cast<VTKRenderer>(viewer->getActiveRenderer()); @@ -119,7 +121,8 @@ main() int count = 0; // The number of times cycling between modes auto updateFunc = - [&](Module*) { + [&](Event*) + { if (count > 15) { count = 0; @@ -169,29 +172,43 @@ main() std::this_thread::sleep_for(std::chrono::milliseconds(500)); }; - simManager->getSceneManager(scene)->setPostUpdateCallback(updateFunc); // Set Camera configuration - auto cam = scene->getCamera(); - cam->setPosition(Vec3d(0, 0, 50)); - cam->setFocalPoint(Vec3d(0, 0, 0)); + scene->getActiveCamera()->setPosition(Vec3d(0.0, 0.0, 50.0)); // Light + imstkNew<DirectionalLight> light1("light1"); + light1->setFocalPoint(Vec3d(-1.0, -1.0, -1.0)); + light1->setIntensity(1.0); + scene->addLight(light1); + + imstkNew<DirectionalLight> light2("light2"); + light2->setFocalPoint(Vec3d(1.0, -1.0, -1.0)); + light2->setIntensity(1.0); + scene->addLight(light2); + + // Run the simulation { - auto light = std::make_shared<DirectionalLight>("Light 1"); - light->setFocalPoint(Vec3d(-1, -1, -1)); - light->setIntensity(1); - scene->addLight(light); - } - { - auto light = std::make_shared<DirectionalLight>("Light 2"); - light->setFocalPoint(Vec3d(1, -1, -1)); - light->setIntensity(1); - scene->addLight(light); + // Setup a scene manager to advance the scene in its own thread + imstkNew<SceneManager> sceneManager("Scene Manager"); + sceneManager->setActiveScene(scene); + viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer + connect<Event>(sceneManager, EventType::PostUpdate, updateFunc); + + // Add mouse and keyboard controls to the viewer + { + imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice()); + mouseControl->setSceneManager(sceneManager); + viewer->addControl(mouseControl); + + imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice()); + keyControl->setSceneManager(sceneManager); + keyControl->setViewer(viewer); + viewer->addControl(keyControl); + } + + viewer->start(); } - // Run - simManager->start(); - return 0; } diff --git a/Examples/DeformableBody/DeformableBodyExample.cpp b/Examples/DeformableBody/DeformableBodyExample.cpp index f6367107bef7acf2a86adbeee6218be9ae8e3952..132aa971517e0c2ec2f64a41e6ac70eab35a2fa8 100644 --- a/Examples/DeformableBody/DeformableBodyExample.cpp +++ b/Examples/DeformableBody/DeformableBodyExample.cpp @@ -19,31 +19,45 @@ =========================================================================*/ -#include "imstkTimer.h" -#include "imstkSimulationManager.h" -#include "imstkFeDeformableObject.h" #include "imstkBackwardEuler.h" -#include "imstkNonLinearSystem.h" -#include "imstkNewtonSolver.h" -#include "imstkGaussSeidel.h" -#include "imstkPlane.h" -#include "imstkTetrahedralMesh.h" -#include "imstkMeshIO.h" -#include "imstkOneToOneMap.h" -#include "imstkAPIUtilities.h" -#include "imstkConjugateGradient.h" -#include "imstkLight.h" #include "imstkCamera.h" +#include "imstkFeDeformableObject.h" #include "imstkFEMDeformableBodyModel.h" -#include "imstkSurfaceMesh.h" +#include "imstkKeyboardSceneControl.h" +#include "imstkLight.h" +#include "imstkLogger.h" +#include "imstkMeshIO.h" +#include "imstkMouseSceneControl.h" +#include "imstkNew.h" +#include "imstkOneToOneMap.h" +#include "imstkPlane.h" +#include "imstkRenderMaterial.h" #include "imstkScene.h" -#include <memory> +#include "imstkSceneManager.h" +#include "imstkSurfaceMesh.h" +#include "imstkTetrahedralMesh.h" +#include "imstkVisualModel.h" +#include "imstkVTKViewer.h" using namespace imstk; -std::shared_ptr<DynamicObject> createAndAddFEDeformable(std::shared_ptr<Scene> scene, std::shared_ptr<PointSet> tetMesh); +std::shared_ptr<DynamicObject> createAndAddFEDeformable(std::shared_ptr<Scene> scene, std::shared_ptr<TetrahedralMesh> tetMesh); + +enum Geom +{ + Dragon = 0, + Heart +}; + +struct Input +{ + std::string meshFileName; + std::vector<std::size_t> fixedNodeIds; +}; -const std::string meshFileName = iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg"; +// Geom geom = Dragon; +const Geom geom = Heart; +Input input; /// /// \brief This example demonstrates the soft body simulation @@ -52,82 +66,114 @@ const std::string meshFileName = iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg"; int main() { - // simManager and Scene - auto simConfig = std::make_shared<SimManagerConfig>(); - simConfig->simulationMode = SimulationMode::Rendering; - auto simManager = std::make_shared<SimulationManager>(simConfig); - auto scene = simManager->createNewScene("DeformableBodyFEM"); - scene->getCamera()->setPosition(0, 2.0, 15.0); - - // Load a tetrahedral mesh - auto tetMesh = MeshIO::read(meshFileName); - - CHECK(tetMesh != nullptr) << "Could not read mesh from file."; - - // Scene object 1: fe-FeDeformableObject - auto deformableObj = createAndAddFEDeformable(scene, tetMesh); - auto dynaModel = std::dynamic_pointer_cast<FEMDeformableBodyModel>(deformableObj->getDynamicalModel()); - - // Scene object 2: Plane - auto planeGeom = std::make_shared<Plane>(); - planeGeom->setWidth(40); - planeGeom->setPosition(0, -6, 0); - auto planeObj = std::make_shared<CollidingObject>("Plane"); - planeObj->setVisualGeometry(planeGeom); - planeObj->setCollidingGeometry(planeGeom); - scene->addSceneObject(planeObj); - - // Light - auto light = std::make_shared<DirectionalLight>("light"); - light->setFocalPoint(Vec3d(5, -8, -5)); - light->setIntensity(1); - scene->addLight(light); + // Setup logger (write to file and stdout) + Logger::startLogger(); + + if (geom == Dragon) + { + input.meshFileName = iMSTK_DATA_ROOT "asianDragon/asianDragon.veg"; + input.fixedNodeIds = { 50, 126, 177 }; + } + else if (geom == Heart) + { + input.meshFileName = iMSTK_DATA_ROOT "/heart/heart.veg"; + input.fixedNodeIds = { 75, 82, 84, 94, 95, 105, 110, 124, 139, 150, 161, 171, 350 }; + } + + // Construct the scene + imstkNew<Scene> scene("DeformableBodyFEM"); + { + std::shared_ptr<Camera> cam = scene->getActiveCamera(); + cam->setPosition(0.0, 2.0, -25.0); + cam->setFocalPoint(0.0, 0.0, 0.0); + + // Load a tetrahedral mesh + auto tetMesh = MeshIO::read<TetrahedralMesh>(input.meshFileName); + CHECK(tetMesh != nullptr) << "Could not read mesh from file."; + + // Scene object 1: fe-FeDeformableObject + std::shared_ptr<DynamicObject> deformableObj = createAndAddFEDeformable(scene, tetMesh); + + // Scene object 2: Plane + imstkNew<Plane> planeGeom; + planeGeom->setWidth(40); + planeGeom->setPosition(0, -6, 0); + imstkNew<CollidingObject> planeObj("Plane"); + planeObj->setVisualGeometry(planeGeom); + planeObj->setCollidingGeometry(planeGeom); + scene->addSceneObject(planeObj); + + // Light + imstkNew<DirectionalLight> light("light"); + light->setFocalPoint(Vec3d(5.0, -8.0, -5.0)); + light->setIntensity(1); + scene->addLight(light); + } // Run the simulation - simManager->setActiveScene(scene); - simManager->start(SimulationStatus::Paused); + { + // Setup a viewer to render in its own thread + imstkNew<VTKViewer> viewer("Viewer 1"); + viewer->setActiveScene(scene); + + // Setup a scene manager to advance the scene in its own thread + imstkNew<SceneManager> sceneManager("Scene Manager 1"); + sceneManager->setActiveScene(scene); + viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer + + // Add mouse and keyboard controls to the viewer + { + imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice()); + mouseControl->setSceneManager(sceneManager); + viewer->addControl(mouseControl); + + imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice()); + keyControl->setSceneManager(sceneManager); + keyControl->setViewer(viewer); + viewer->addControl(keyControl); + } + + // Start viewer running, scene as paused + sceneManager->requestStatus(ThreadStatus::Paused); + viewer->start(); + } return 0; } std::shared_ptr<DynamicObject> -createAndAddFEDeformable(std::shared_ptr<Scene> scene, - std::shared_ptr<PointSet> tetMesh) +createAndAddFEDeformable(std::shared_ptr<Scene> scene, + std::shared_ptr<TetrahedralMesh> tetMesh) { - auto volTetMesh = std::dynamic_pointer_cast<TetrahedralMesh>(tetMesh); - CHECK(volTetMesh != nullptr) << "Dynamic pointer cast from PointSet to TetrahedralMesh failed!"; - auto surfMesh = std::make_shared<SurfaceMesh>(); - volTetMesh->extractSurfaceMesh(surfMesh, true); + imstkNew<SurfaceMesh> surfMesh; + tetMesh->extractSurfaceMesh(surfMesh, true); // Configure dynamic model - auto dynaModel = std::make_shared<FEMDeformableBodyModel>(); - auto config = std::make_shared<FEMModelConfig>(); - config->m_fixedNodeIds = { 50, 126, 177 }; + imstkNew<FEMDeformableBodyModel> dynaModel; + imstkNew<FEMModelConfig> config; + config->m_fixedNodeIds = input.fixedNodeIds; dynaModel->configure(config); //dynaModel->configure(iMSTK_DATA_ROOT "/asianDragon/asianDragon.config"); dynaModel->setTimeStepSizeType(TimeSteppingType::Fixed); - dynaModel->setModelGeometry(volTetMesh); - auto timeIntegrator = std::make_shared<BackwardEuler>(0.01);// Create and add Backward Euler time integrator + dynaModel->setModelGeometry(tetMesh); + imstkNew<BackwardEuler> timeIntegrator(0.01); // Create and add Backward Euler time integrator dynaModel->setTimeIntegrator(timeIntegrator); - auto material = std::make_shared<RenderMaterial>(); - material->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface); - material->setPointSize(10.); - material->setLineWidth(4.); - material->setEdgeColor(Color::Color::Orange); - auto surfMeshModel = std::make_shared<VisualModel>(surfMesh); - surfMeshModel->setRenderMaterial(material); + imstkNew<RenderMaterial> mat; + mat->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface); + mat->setPointSize(10.); + mat->setLineWidth(4.); + mat->setEdgeColor(Color::Orange); + imstkNew<VisualModel> surfMeshModel(surfMesh.get()); + surfMeshModel->setRenderMaterial(mat); // Scene object 1: Dragon - auto deformableObj = std::make_shared<FeDeformableObject>("Dragon"); + imstkNew<FeDeformableObject> deformableObj("Dragon"); deformableObj->addVisualModel(surfMeshModel); - - deformableObj->setPhysicsGeometry(volTetMesh); - - // Construct one to one nodal map based on the above meshes - auto oneToOneNodalMap = std::make_shared<OneToOneMap>(tetMesh, surfMesh); - deformableObj->setPhysicsToVisualMap(oneToOneNodalMap); //assign the computed map + deformableObj->setPhysicsGeometry(tetMesh); + // Map simulated geometry to visual + deformableObj->setPhysicsToVisualMap(std::make_shared<OneToOneMap>(tetMesh, surfMesh)); deformableObj->setDynamicalModel(dynaModel); scene->addSceneObject(deformableObj); diff --git a/Examples/GeometryProcessing/CMakeLists.txt b/Examples/GeometryProcessing/CMakeLists.txt index 9ed9446ba528efa332d3fcfd57371fa9ff47f766..0abe14903b4ffbda995eaa3d783c1fe8e8f9b060 100644 --- a/Examples/GeometryProcessing/CMakeLists.txt +++ b/Examples/GeometryProcessing/CMakeLists.txt @@ -31,4 +31,4 @@ SET_TARGET_PROPERTIES (${PROJECT_NAME} PROPERTIES FOLDER Examples) #----------------------------------------------------------------------------- # Link libraries to executable #----------------------------------------------------------------------------- -target_link_libraries(${PROJECT_NAME} SimulationManager apiUtilities) +target_link_libraries(${PROJECT_NAME} SimulationManager apiUtilities Filtering) diff --git a/Examples/GeometryProcessing/GeometryProcessingExample.cpp b/Examples/GeometryProcessing/GeometryProcessingExample.cpp index 5a050fb534c2aed0e2fb9882bb9154c8ffe4b1ab..c0a793d99f05e195931c06d1c726b0a2289d25b6 100644 --- a/Examples/GeometryProcessing/GeometryProcessingExample.cpp +++ b/Examples/GeometryProcessing/GeometryProcessingExample.cpp @@ -19,81 +19,114 @@ =========================================================================*/ -#include "imstkSimulationManager.h" -#include "imstkSceneObject.h" -#include "imstkLight.h" -#include "imstkPlane.h" -#include "imstkCylinder.h" -#include "imstkCube.h" -#include "imstkAPIUtilities.h" -#include "imstkGeometryUtilities.h" #include "imstkCamera.h" +#include "imstkDataArray.h" +#include "imstkImageData.h" +#include "imstkLight.h" +#include "imstkLogger.h" #include "imstkMeshIO.h" +#include "imstkNew.h" +#include "imstkQuadricDecimate.h" +#include "imstkRenderMaterial.h" +#include "imstkScene.h" +#include "imstkSceneManager.h" +#include "imstkSceneObject.h" #include "imstkSurfaceMesh.h" +#include "imstkSurfaceMeshDistanceTransform.h" +#include "imstkSurfaceMeshFlyingEdges.h" #include "imstkTetrahedralMesh.h" -#include "imstkScene.h" +#include "imstkVisualModel.h" +#include "imstkVTKViewer.h" using namespace imstk; /// -/// \brief This example demonstrates the geometry transforms in imstk +/// \brief This example demonstrates erosion of a mesh /// int main() { + Logger::startLogger(); + // simManager and Scene - auto simManager = std::make_shared<SimulationManager>(); - auto scene = simManager->createNewScene("GeometryTransforms"); + imstkNew<Scene> scene("GeometryProcessing"); - auto coarseTetMesh = std::dynamic_pointer_cast<TetrahedralMesh>(MeshIO::read(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg")); - auto coarseSurfMesh = std::make_shared<SurfaceMesh>(); + auto coarseTetMesh = MeshIO::read<TetrahedralMesh>(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg"); + imstkNew<SurfaceMesh> coarseSurfMesh; coarseTetMesh->extractSurfaceMesh(coarseSurfMesh, true); - std::shared_ptr<SurfaceMesh> fineSurfaceMesh(std::move(GeometryUtils::loopSubdivideSurfaceMesh(coarseSurfMesh))); - - fineSurfaceMesh->translate(Vec3d(0., -5., 0.), Geometry::TransformType::ConcatenateToTransform); - coarseSurfMesh->translate(Vec3d(0., 5., 0.), Geometry::TransformType::ConcatenateToTransform); - - auto material0 = std::make_shared<RenderMaterial>(); - material0->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface); - material0->setPointSize(10.); - material0->setLineWidth(4.); - material0->setEdgeColor(Color::Color::Orange); - auto surfMeshModel0 = std::make_shared<VisualModel>(coarseSurfMesh); - surfMeshModel0->setRenderMaterial(material0); - - auto sceneObj0 = std::make_shared<VisualObject>("coarse Mesh"); - sceneObj0->addVisualModel(surfMeshModel0); - - scene->addSceneObject(sceneObj0); - - auto material = std::make_shared<RenderMaterial>(); - material->setColor(imstk::Color::Red); - material->setDisplayMode(RenderMaterial::DisplayMode::Wireframe); - material->setPointSize(6.); - material->setLineWidth(1.); - auto surfMeshModel = std::make_shared<VisualModel>(fineSurfaceMesh); - surfMeshModel->setRenderMaterial(material); - - auto sceneObj = std::make_shared<VisualObject>("fine Mesh"); - sceneObj->addVisualModel(surfMeshModel); - + // Compute DT + imstkNew<SurfaceMeshDistanceTransform> createSdf; + createSdf->setInputMesh(coarseSurfMesh); + createSdf->setDimensions(150, 150, 150); + createSdf->update(); + + // Erode + const double erosionDist = 0.2; + DataArray<double>& scalars = *std::dynamic_pointer_cast<DataArray<double>>(createSdf->getOutputImage()->getScalars()); + for (size_t i = 0; i < scalars.size(); i++) + { + scalars[i] += erosionDist; + } + + // Extract surface + imstkNew<SurfaceMeshFlyingEdges> isoExtract; + isoExtract->setInputImage(createSdf->getOutputImage()); + isoExtract->update(); + + // Reduce surface + imstkNew<QuadricDecimate> reduce; + reduce->setInputMesh(isoExtract->getOutputMesh()); + reduce->setTargetReduction(0.5); + reduce->update(); + + // Create the scene object + imstkNew<VisualObject> sceneObj("Mesh"); + // Create the eroded visual model + { + imstkNew<VisualModel> surfMeshModel(reduce->getOutput()); + imstkNew<RenderMaterial> material; + material->setDisplayMode(RenderMaterial::DisplayMode::Surface); + material->setLineWidth(4.0); + material->setEdgeColor(Color::Color::Orange); + surfMeshModel->setRenderMaterial(material); + sceneObj->addVisualModel(surfMeshModel); + } + // Create the original mesh visual model + { + imstkNew<VisualModel> surfMeshModel(coarseSurfMesh.get()); + imstkNew<RenderMaterial> material; + material->setColor(imstk::Color::Red); + material->setDisplayMode(RenderMaterial::DisplayMode::Surface); + material->setLineWidth(1.0); + material->setOpacity(0.2f); + surfMeshModel->setRenderMaterial(material); + sceneObj->addVisualModel(surfMeshModel); + } scene->addSceneObject(sceneObj); // Set Camera configuration - auto cam = scene->getCamera(); - cam->setPosition(Vec3d(0, 12, 12)); - cam->setFocalPoint(Vec3d(0, 0, 0)); + scene->getActiveCamera()->setPosition(Vec3d(0.0, 12.0, 12.0)); // Light - auto light = std::make_shared<DirectionalLight>("light"); - light->setFocalPoint(Vec3d(5, -8, -5)); + imstkNew<DirectionalLight> light("light"); + light->setFocalPoint(Vec3d(5.0, -8.0, -5.0)); light->setIntensity(1); scene->addLight(light); - // Run - simManager->setActiveScene(scene); - simManager->start(SimulationStatus::Running); + // Run the simulation + { + // Setup a viewer to render in its own thread + imstkNew<VTKViewer> viewer("Viewer"); + viewer->setActiveScene(scene); + + // Setup a scene manager to advance the scene in its own thread + imstkNew<SceneManager> sceneManager("Scene Manager"); + sceneManager->setActiveScene(scene); + viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer + + viewer->start(); + } return 0; } diff --git a/Examples/GeometryTransforms/GeometryTransformsExample.cpp b/Examples/GeometryTransforms/GeometryTransformsExample.cpp index f80e4ef7b770d4e51f135fc793b9e1d6feacf263..ed6a7608206208986eb58dacd6fdb476d0737205 100644 --- a/Examples/GeometryTransforms/GeometryTransformsExample.cpp +++ b/Examples/GeometryTransforms/GeometryTransformsExample.cpp @@ -19,16 +19,22 @@ =========================================================================*/ -#include "imstkSimulationManager.h" -#include "imstkSceneManager.h" -#include "imstkSceneObject.h" +#include "imstkAPIUtilities.h" #include "imstkCamera.h" +#include "imstkCube.h" +#include "imstkCylinder.h" +#include "imstkKeyboardSceneControl.h" #include "imstkLight.h" +#include "imstkLogger.h" +#include "imstkMouseSceneControl.h" +#include "imstkNew.h" #include "imstkPlane.h" -#include "imstkCylinder.h" -#include "imstkCube.h" -#include "imstkAPIUtilities.h" +#include "imstkRenderMaterial.h" #include "imstkScene.h" +#include "imstkSceneManager.h" +#include "imstkSceneObject.h" +#include "imstkVisualModel.h" +#include "imstkVTKViewer.h" using namespace imstk; @@ -38,96 +44,116 @@ using namespace imstk; int main() { - // simManager and Scene - auto simManager = std::make_shared<SimulationManager>(); - auto scene = simManager->createNewScene("GeometryTransforms"); + // Setup logger (write to file and stdout) + Logger::startLogger(); + + imstkNew<Scene> scene("GeometryTransforms"); auto sceneObj = apiutils::createAndAddVisualSceneObject(scene, iMSTK_DATA_ROOT "/asianDragon/asianDragon.obj", "Dragon"); CHECK(sceneObj != nullptr) << "ERROR: Unable to create scene object"; auto surfaceMesh = sceneObj->getVisualGeometry(); - surfaceMesh->scale(5., Geometry::TransformType::ConcatenateToTransform); + surfaceMesh->scale(5.0, Geometry::TransformType::ConcatenateToTransform); // Plane - auto planeGeom = std::make_shared<Plane>(); - planeGeom->scale(80, Geometry::TransformType::ConcatenateToTransform); - planeGeom->translate(0, -20, 0, Geometry::TransformType::ConcatenateToTransform); - planeGeom->rotate(Vec3d(0, 1., 0), PI / 4, Geometry::TransformType::ConcatenateToTransform); - - auto materialPlane = std::make_shared<RenderMaterial>(); - materialPlane->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface); - materialPlane->setPointSize(6.); - materialPlane->setLineWidth(4.); - auto planeVizModel = std::make_shared<VisualModel>(planeGeom); - planeVizModel->setRenderMaterial(materialPlane); - - auto planeObj = std::make_shared<VisualObject>("Plane"); + imstkNew<Plane> planeGeom; + planeGeom->scale(80.0, Geometry::TransformType::ConcatenateToTransform); + planeGeom->translate(0.0, -20.0, 0.0, Geometry::TransformType::ConcatenateToTransform); + planeGeom->rotate(Vec3d(0.0, 1.0, 0.0), PI_4, Geometry::TransformType::ConcatenateToTransform); + + imstkNew<RenderMaterial> planeMaterial; + planeMaterial->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface); + planeMaterial->setPointSize(6.); + planeMaterial->setLineWidth(4.); + imstkNew<VisualModel> planeVisualModel(planeGeom.get()); + planeVisualModel->setRenderMaterial(planeMaterial); + + imstkNew<VisualObject> planeObj("Plane"); //planeObj->setVisualGeometry(planeGeom); - planeObj->addVisualModel(planeVizModel); + planeObj->addVisualModel(planeVisualModel); scene->addSceneObject(planeObj); // Cube - auto cubeGeom = std::make_shared<Cube>(); - cubeGeom->setWidth(20.); + imstkNew<Cube> cubeGeom; + cubeGeom->setWidth(20.0); cubeGeom->scale(0.5, Geometry::TransformType::ConcatenateToTransform); - cubeGeom->rotate(Vec3d(1., 1., 0), PI / 4, Geometry::TransformType::ApplyToData); - - auto materialCube = std::make_shared<RenderMaterial>(); - materialCube->setColor(imstk::Color::Red); - materialCube->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface); - materialCube->setPointSize(6.); - materialCube->setLineWidth(4.); - auto cubeVizModel = std::make_shared<VisualModel>(cubeGeom); - cubeVizModel->setRenderMaterial(materialCube); - - auto cubeObj = std::make_shared<VisualObject>("Cube"); - //cubeObj->setVisualGeometry(cubeGeom); - cubeObj->addVisualModel(cubeVizModel); + cubeGeom->rotate(Vec3d(1.0, 1.0, 0.0), PI_4, Geometry::TransformType::ApplyToData); + + auto materialCube = std::make_shared<RenderMaterial>(); + imstkNew<RenderMaterial> cubeMaterial; + cubeMaterial->setColor(imstk::Color::Red); + cubeMaterial->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface); + cubeMaterial->setPointSize(6.); + cubeMaterial->setLineWidth(4.); + imstkNew<VisualModel> cubeVisualModel(cubeGeom.get()); + cubeVisualModel->setRenderMaterial(cubeMaterial); + + imstkNew<VisualObject> cubeObj("Cube"); + cubeObj->addVisualModel(cubeVisualModel); scene->addSceneObject(cubeObj); // Cylinder - auto CylinderGeom = std::make_shared<Cylinder>(); - CylinderGeom->setRadius(4.); - CylinderGeom->setLength(8.); - CylinderGeom->scale(0.4, Geometry::TransformType::ConcatenateToTransform); - CylinderGeom->rotate(Vec3d(1., 1., 0), PI / 2, Geometry::TransformType::ApplyToData); - - auto materialCyl = std::make_shared<RenderMaterial>(); - materialCyl->setColor(imstk::Color::Red); - materialCyl->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface); - materialCyl->setPointSize(6.); - materialCyl->setLineWidth(4.); - auto cylVizModel = std::make_shared<VisualModel>(CylinderGeom); - cylVizModel->setRenderMaterial(materialCube); - - auto CylinderObj = std::make_shared<VisualObject>("Cylinder"); - //CylinderObj->setVisualGeometry(CylinderGeom); - CylinderObj->addVisualModel(cylVizModel); - scene->addSceneObject(CylinderObj); - - // Rotate the dragon every frame + imstkNew<Cylinder> cylinderGeom; + cylinderGeom->setRadius(4.0); + cylinderGeom->setLength(8.0); + cylinderGeom->scale(0.4, Geometry::TransformType::ConcatenateToTransform); + cylinderGeom->rotate(Vec3d(1.0, 1.0, 0), PI_2, Geometry::TransformType::ApplyToData); + + imstkNew<RenderMaterial> cylMaterial; + cylMaterial->setColor(imstk::Color::Red); + cylMaterial->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface); + cylMaterial->setPointSize(6.0); + cylMaterial->setLineWidth(4.0); + imstkNew<VisualModel> cylVisualModel(cylinderGeom.get()); + cylVisualModel->setRenderMaterial(materialCube); + + imstkNew<VisualObject> cylObj("Cylinder"); + cylObj->addVisualModel(cylVisualModel); + scene->addSceneObject(cylObj); + + // Setup function to rotate the dragon every frame auto rotateFunc = - [&surfaceMesh](Module* module) + [&surfaceMesh](Event*) { - surfaceMesh->rotate(Vec3d(1., 0, 0), PI / 1000, Geometry::TransformType::ApplyToData); + surfaceMesh->rotate(Vec3d(1.0, 0.0, 0.0), PI * 0.0001, Geometry::TransformType::ApplyToData); }; - simManager->getSceneManager(scene)->setPostUpdateCallback(rotateFunc); // Set Camera configuration - auto cam = scene->getCamera(); - cam->setPosition(Vec3d(0, 30, 30)); - cam->setFocalPoint(Vec3d(0, 0, 0)); + scene->getActiveCamera()->setPosition(Vec3d(0.0, 30.0, 30.0)); // Light - auto light = std::make_shared<DirectionalLight>("light"); - light->setFocalPoint(Vec3d(5, -8, -5)); - light->setIntensity(1); + imstkNew<DirectionalLight> light("light"); + light->setDirection(Vec3d(5.0, -8.0, -5.0)); + light->setIntensity(1.0); scene->addLight(light); - // Run - simManager->setActiveScene(scene); - simManager->start(SimulationStatus::Running); + // Run the simulation + { + // Setup a viewer to render in its own thread + imstkNew<VTKViewer> viewer("Viewer"); + viewer->setActiveScene(scene); + + // Setup a scene manager to advance the scene in its own thread + imstkNew<SceneManager> sceneManager("Scene Manager"); + sceneManager->setActiveScene(scene); + viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer + connect<Event>(sceneManager, EventType::PostUpdate, rotateFunc); + + // Add mouse and keyboard controls to the viewer + { + imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice()); + mouseControl->setSceneManager(sceneManager); + viewer->addControl(mouseControl); + + imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice()); + keyControl->setSceneManager(sceneManager); + keyControl->setViewer(viewer); + viewer->addControl(keyControl); + } + + viewer->start(); + } return 0; } diff --git a/Examples/Graph/GraphExample.cpp b/Examples/Graph/GraphExample.cpp index 7dff368ab5dff171bca762583a999232736ef5dc..a1f2aeb36510fb1301b3fa01228590d7847315af 100644 --- a/Examples/Graph/GraphExample.cpp +++ b/Examples/Graph/GraphExample.cpp @@ -19,13 +19,13 @@ =========================================================================*/ +#include "imstkAPIUtilities.h" #include "imstkGraph.h" -#include "imstkTetrahedralMesh.h" +#include "imstkLogger.h" #include "imstkMeshIO.h" -#include "imstkAPIUtilities.h" +#include "imstkNew.h" #include "imstkSurfaceMesh.h" - -#include <iostream> +#include "imstkTetrahedralMesh.h" using namespace imstk; @@ -37,6 +37,8 @@ using namespace imstk; int main(int argc, char** argv) { + Logger::startLogger(); + // Using WelshPowell method by default Graph::ColoringMethod method = Graph::ColoringMethod::WelshPowell; @@ -83,23 +85,22 @@ main(int argc, char** argv) g2.print(); auto colorsG2 = g2.doColoring(method, true); - auto tetMesh = MeshIO::read(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg"); + auto tetMesh = MeshIO::read<TetrahedralMesh>(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg"); if (!tetMesh) { - std::cout << "Could not read mesh from file." << std::endl; + LOG(INFO) << "Could not read mesh from file."; return 1; } else { - auto volMesh = std::dynamic_pointer_cast<TetrahedralMesh>(tetMesh); - auto colorsGVMesh = apiutils::getMeshGraph(volMesh)->doColoring(method, true); + auto colorsGVMesh = apiutils::getMeshGraph(tetMesh)->doColoring(method, true); - auto surfMesh = std::make_shared<SurfaceMesh>(); - volMesh->extractSurfaceMesh(surfMesh, true); - auto colorsGSMesh = apiutils::getMeshGraph(surfMesh)->doColoring(method, true); + imstkNew<SurfaceMesh> surfMesh; + tetMesh->extractSurfaceMesh(surfMesh, true); + auto colorsGSMesh = apiutils::getMeshGraph(surfMesh.get())->doColoring(method, true); } - std::cout << "Press any key to exit!" << std::endl; + LOG(INFO) << "Press any key to exit!"; getchar(); return 0; diff --git a/Examples/Interactions/CMakeLists.txt b/Examples/Interactions/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..964a9fe46555e89800ccc1ca30875fc8ac896dab --- /dev/null +++ b/Examples/Interactions/CMakeLists.txt @@ -0,0 +1,21 @@ +#----------------------------------------------------------------------------- +# Add Example subdirectories +#----------------------------------------------------------------------------- +macro(listOfSubDir result curdir) + file(GLOB children RELATIVE ${curdir} ${curdir}/*) + set(dirlist "") + foreach(child ${children}) + if(IS_DIRECTORY ${curdir}/${child}) + list(APPEND dirlist ${child}) + endif() + endforeach() + set(${result} ${dirlist}) +endmacro() + +listOfSubDir(subDirs ${CMAKE_CURRENT_SOURCE_DIR}) + +foreach(subdir ${subDirs}) + add_subdirectory(${subdir}) +endforeach() + + diff --git a/Examples/Interactions/LevelSet-Rigid/CMakeLists.txt b/Examples/Interactions/LevelSet-Rigid/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..19424ad9054a3e7a6ff888831d6fa51f2350a0fc --- /dev/null +++ b/Examples/Interactions/LevelSet-Rigid/CMakeLists.txt @@ -0,0 +1,34 @@ +########################################################################### +# +# Copyright (c) Kitware, Inc. +# +# 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. +# +########################################################################### + +project(Example-LevelSet-RigidInteraction) + +#----------------------------------------------------------------------------- +# Create executable +#----------------------------------------------------------------------------- +imstk_add_executable(${PROJECT_NAME} LevelSet-RigidInteractionExample.cpp) + +#----------------------------------------------------------------------------- +# Add the target to Examples folder +#----------------------------------------------------------------------------- +SET_TARGET_PROPERTIES (${PROJECT_NAME} PROPERTIES FOLDER Examples/Interaction) + +#----------------------------------------------------------------------------- +# Link libraries to executable +#----------------------------------------------------------------------------- +target_link_libraries(${PROJECT_NAME} SimulationManager Filtering) diff --git a/Examples/Interactions/LevelSet-Rigid/LevelSet-RigidInteractionExample.cpp b/Examples/Interactions/LevelSet-Rigid/LevelSet-RigidInteractionExample.cpp new file mode 100644 index 0000000000000000000000000000000000000000..da7be12fd68c495bfe2a5626b9536cd72870346d --- /dev/null +++ b/Examples/Interactions/LevelSet-Rigid/LevelSet-RigidInteractionExample.cpp @@ -0,0 +1,229 @@ +/*========================================================================= + + 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 "imstkCamera.h" +#include "imstkCollisionGraph.h" +#include "imstkImageData.h" +#include "imstkImplicitGeometryToImageData.h" +#include "imstkLevelSetDeformableObject.h" +#include "imstkLevelSetModel.h" +#include "imstkLight.h" +#include "imstkLogger.h" +#include "imstkMeshIO.h" +#include "imstkNew.h" +#include "imstkOpenVRDeviceClient.h" +#include "imstkPlane.h" +#include "imstkRbdConstraint.h" +#include "imstkRigidBodyModel2.h" +#include "imstkRigidObject2.h" +#include "imstkRigidObjectController.h" +#include "imstkRigidObjectLevelSetCollisionPair.h" +#include "imstkScene.h" +#include "imstkSceneManager.h" +#include "imstkSurfaceMesh.h" +#include "imstkSurfaceMeshFlyingEdges.h" +#include "imstkVisualModel.h" +#include "imstkVolumeRenderMaterial.h" +#include "imstkVTKOpenVRViewer.h" +#include <vtkColorTransferFunction.h> +#include <vtkPiecewiseFunction.h> +#include <vtkVolumeProperty.h> +#include "imstkSurfaceMeshSubdivide.h" + +using namespace imstk; +using namespace imstk::expiremental; + +/// +/// \brief Creates cloth object +/// +std::shared_ptr<LevelSetDeformableObject> +makeLevelsetObj(const std::string& name) +{ + imstkNew<LevelSetDeformableObject> levelsetObj(name); + + std::shared_ptr<ImageData> initLvlsetImage = MeshIO::read<ImageData>(iMSTK_DATA_ROOT "/legs/femurBone_SDF.nii")->cast(IMSTK_DOUBLE); + const Vec3d& currSpacing = initLvlsetImage->getSpacing(); + initLvlsetImage->setSpacing(currSpacing * 0.0015); + initLvlsetImage->setOrigin(Vec3d(0.0, 1.0, -2.0)); + + // Setup the Parameters + imstkNew<LevelSetModelConfig> lvlSetConfig; + lvlSetConfig->m_sparseUpdate = true; + lvlSetConfig->m_dt = 0.001; + + // Setup the Model + imstkNew<LevelSetModel> model; + model->setModelGeometry(initLvlsetImage); + model->configure(lvlSetConfig); + + // Setup the VisualModel + imstkNew<VisualModel> visualModel(initLvlsetImage); + imstkNew<VolumeRenderMaterial> mat; + { + vtkNew<vtkColorTransferFunction> color; + color->AddRGBPoint(0.0, 0.75, 0.73, 0.66); + mat->getVolumeProperty()->SetColor(color); + vtkNew<vtkPiecewiseFunction> opacity; + opacity->AddPoint(0.0, 0.0); + opacity->AddPoint(-0.001, 1.0); + mat->getVolumeProperty()->SetScalarOpacity(opacity); + mat->getVolumeProperty()->SetInterpolationTypeToLinear(); + mat->getVolumeProperty()->ShadeOn(); + } + visualModel->setRenderMaterial(mat); + + // Setup the Object + levelsetObj->addVisualModel(visualModel); + levelsetObj->setPhysicsGeometry(initLvlsetImage); + levelsetObj->setCollidingGeometry(std::make_shared<SignedDistanceField>(initLvlsetImage)); + levelsetObj->setDynamicalModel(model); + + return levelsetObj; +} + +std::shared_ptr<CollidingObject> +makeCollidingObject(const std::string& name) +{ + imstkNew<CollidingObject> collideObj(name); + + // Setup a plane, then cut with a sphere + imstkNew<Plane> plane(Vec3d(0.0, 0.0, 0.0), Vec3d(0.0, 1.0, 0.0)); + + // Put into an image + imstkNew<ImplicitGeometryToImageData> toSdf; + toSdf->setInputGeometry(plane); + Vec6d bounds; + bounds[0] = -5.0; + bounds[1] = 5.0; + bounds[2] = -5.0; + bounds[3] = 5.0; + bounds[4] = -5.0; + bounds[5] = 5.0; + toSdf->setBounds(bounds); + toSdf->setDimensions(Vec3i(35, 35, 35)); + toSdf->update(); + std::shared_ptr<ImageData> initLvlsetImage = toSdf->getOutputImage(); + + imstkNew<SurfaceMeshFlyingEdges> isoExtract; + isoExtract->setInputImage(initLvlsetImage); + isoExtract->update(); + + // Setup the VisualModel + imstkNew<VisualModel> visualModel(isoExtract->getOutputMesh()); + + // Setup the Object + collideObj->addVisualModel(visualModel); + collideObj->setCollidingGeometry(std::make_shared<SignedDistanceField>(initLvlsetImage)); + + return collideObj; +} + +std::shared_ptr<RigidObject2> +makeRigidObj(const std::string& name) +{ + imstkNew<RigidBodyModel2> rbdModel; + rbdModel->getConfig()->m_dt = 0.0005; + rbdModel->getConfig()->m_maxNumIterations = 10; + + // Create the first rbd, plane floor + imstkNew<RigidObject2> rigidObj("Cube"); + + { + auto toolMesh = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/Surgical Instruments/Scalpel/Scalpel_Blade10_Hull.stl"); + toolMesh->rotate(Vec3d(0.0, 1.0, 0.0), 3.14, Geometry::TransformType::ApplyToData); + toolMesh->rotate(Vec3d(1.0, 0.0, 0.0), -1.57, Geometry::TransformType::ApplyToData); + toolMesh->scale(0.07, Geometry::TransformType::ApplyToData); + + imstkNew<VisualModel> visualModel(toolMesh); + imstkNew<RenderMaterial> mat; + mat->setDisplayMode(RenderMaterial::DisplayMode::Surface); + mat->setShadingModel(RenderMaterial::ShadingModel::PBR); + mat->setMetalness(0.9f); + mat->setRoughness(0.2f); + //mat->setDisplayMode(RenderMaterial::DisplayMode::Points); + //mat->setPointSize(15.0); + visualModel->setRenderMaterial(mat); + + // Create the object + rigidObj->addVisualModel(visualModel); + rigidObj->setPhysicsGeometry(toolMesh); + rigidObj->setCollidingGeometry(toolMesh); + rigidObj->setVisualGeometry(toolMesh); + rigidObj->setDynamicalModel(rbdModel); + rigidObj->getRigidBody()->m_mass = 100.0; + rigidObj->getRigidBody()->setInertiaFromPointSet(toolMesh, 0.01, false); + rigidObj->getRigidBody()->m_initPos = Vec3d(0.0, 2.0, 0.0); + } + return rigidObj; +} + +/// +/// \brief This example demonstrates evolution of a levelset +/// +int +main() +{ + // Setup logger (write to file and stdout) + Logger::startLogger(); + + imstkNew<Scene> scene("LevelsetDeformable"); + scene->getConfig()->writeTaskGraph = true; + + std::shared_ptr<LevelSetDeformableObject> lvlSetObj = makeLevelsetObj("LevelSetObj"); + scene->addSceneObject(lvlSetObj); + + std::shared_ptr<RigidObject2> rbdObj = makeRigidObj("RigidObj"); + scene->addSceneObject(rbdObj); + + imstkNew<RigidObjectLevelSetCollisionPair> interaction(rbdObj, lvlSetObj); + scene->getCollisionGraph()->addInteraction(interaction); + + // Light (white) + imstkNew<DirectionalLight> whiteLight("whiteLight"); + whiteLight->setFocalPoint(Vec3d(5.0, -8.0, -5.0)); + whiteLight->setIntensity(1.0); + scene->addLight(whiteLight); + + // Adjust camera + scene->getActiveCamera()->setFocalPoint(0.0, 0.0, 0.0); + scene->getActiveCamera()->setPosition(0.0, 10.0, -10.0); + + { + // Add a module to run the viewer + imstkNew<VTKOpenVRViewer> viewer("VRViewer"); + viewer->setActiveScene(scene); + + // Add a module to run the scene + imstkNew<SceneManager> sceneManager("Scene Manager"); + sceneManager->setActiveScene(scene); + viewer->addChildThread(sceneManager); // Start/stop scene with the view + + // Add a VR controller for the sceneobject + imstkNew<RigidObjectController> controller(rbdObj, viewer->getVRDeviceClient(OPENVR_RIGHT_CONTROLLER)); + scene->addController(controller); + + // Start running + viewer->requestStatus(ThreadStatus::Running); + viewer->start(); + } + + return 0; +} \ No newline at end of file diff --git a/Examples/Interactions/SPH-Obj-SDF/CMakeLists.txt b/Examples/Interactions/SPH-Obj-SDF/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..ad294696502c30bb76b709361ee4d9c7dcbbd63e --- /dev/null +++ b/Examples/Interactions/SPH-Obj-SDF/CMakeLists.txt @@ -0,0 +1,34 @@ +########################################################################### +# +# Copyright (c) Kitware, Inc. +# +# 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. +# +########################################################################### + +project(Example-SPH-Obj-SDFInteraction) + +#----------------------------------------------------------------------------- +# Create executable +#----------------------------------------------------------------------------- +imstk_add_executable(${PROJECT_NAME} SPH-Obj-SDFInteractionExample.cpp) + +#----------------------------------------------------------------------------- +# Add the target to Examples folder +#----------------------------------------------------------------------------- +SET_TARGET_PROPERTIES (${PROJECT_NAME} PROPERTIES FOLDER Examples/Interaction) + +#----------------------------------------------------------------------------- +# Link libraries to executable +#----------------------------------------------------------------------------- +target_link_libraries(${PROJECT_NAME} SimulationManager Filtering) diff --git a/Examples/Interactions/SPH-Obj-SDF/SPH-Obj-SDFInteractionExample.cpp b/Examples/Interactions/SPH-Obj-SDF/SPH-Obj-SDFInteractionExample.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1978990498370eeff54da7932fbb9ef75684a36b --- /dev/null +++ b/Examples/Interactions/SPH-Obj-SDF/SPH-Obj-SDFInteractionExample.cpp @@ -0,0 +1,219 @@ +/*========================================================================= + + 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 "imstkCamera.h" +#include "imstkCollisionGraph.h" +#include "imstkKeyboardSceneControl.h" +#include "imstkLight.h" +#include "imstkMeshIO.h" +#include "imstkMouseSceneControl.h" +#include "imstkNew.h" +#include "imstkRenderMaterial.h" +#include "imstkScene.h" +#include "imstkSceneManager.h" +#include "imstkSignedDistanceField.h" +#include "imstkSPHModel.h" +#include "imstkSPHObject.h" +#include "imstkSphObjectCollisionPair.h" +#include "imstkSurfaceMesh.h" +#include "imstkSurfaceMeshDistanceTransform.h" +#include "imstkViewer.h" +#include "imstkVisualModel.h" +#include "imstkVTKViewer.h" + +using namespace imstk; + +/// +/// \brief Generate a box-shape of fluid particles +/// +std::shared_ptr<StdVectorOfVec3d> +generateBoxShapeFluid(const double particleRadius, const Vec3d& boxCenter, const Vec3d& boxSize) +{ + double bounds[6] = + { + boxCenter.x() - boxSize.x() * 0.5, + boxCenter.x() + boxSize.x() * 0.5, + boxCenter.y() - boxSize.y() * 0.5, + boxCenter.y() + boxSize.y() * 0.5, + boxCenter.z() - boxSize.z() * 0.5, + boxCenter.z() + boxSize.z() * 0.5 + }; + + const double spacing = 2.0 * particleRadius; + const Vec3i dim = { + static_cast<int>(boxSize.x() / spacing), + static_cast<int>(boxSize.y() / spacing), + static_cast<int>(boxSize.z() / spacing) }; + + imstkNew<StdVectorOfVec3d> particles; + particles->reserve(dim[0] * dim[1] * dim[2]); + + for (double z = bounds[4]; z < bounds[5]; z += spacing) + { + for (double y = bounds[2]; y < bounds[3]; y += spacing) + { + for (double x = bounds[0]; x < bounds[1]; x += spacing) + { + particles->push_back(Vec3d(x, y, z)); + } + } + } + + return particles; +} + +std::shared_ptr<SPHObject> +makeSPHBoxObject(const std::string& name, const double particleRadius, const Vec3d& boxShift, const Vec3d& boxSize) +{ + // Create the sph object + imstkNew<SPHObject> fluidObj(name); + + // Setup the Geometry + std::shared_ptr<StdVectorOfVec3d> particles = generateBoxShapeFluid(particleRadius, boxShift, boxSize); + LOG(INFO) << "Number of particles: " << particles->size(); + imstkNew<PointSet> fluidGeometry; + fluidGeometry->initialize(*particles); + + // Setup the Parameters + imstkNew<SPHModelConfig> sphParams(particleRadius); + sphParams->m_bNormalizeDensity = true; + sphParams->m_kernelOverParticleRadiusRatio = 6.0; + sphParams->m_viscosityCoeff = 0.5; + sphParams->m_surfaceTensionStiffness = 5.0; + sphParams->m_gravity = Vec3d(0.0, -70.0, 0.0); + + // Setup the Model + imstkNew<SPHModel> sphModel; + sphModel->setModelGeometry(fluidGeometry); + sphModel->configure(sphParams); + sphModel->setTimeStepSizeType(TimeSteppingType::RealTime); + + // Setup the VisualModel + imstkNew<VisualModel> fluidVisualModel(fluidGeometry.get()); + imstkNew<RenderMaterial> fluidMaterial; + fluidMaterial->setDisplayMode(RenderMaterial::DisplayMode::Fluid); + fluidMaterial->setVertexColor(Color::Orange); + fluidMaterial->setPointSize(static_cast<float>(particleRadius)); + fluidVisualModel->setRenderMaterial(fluidMaterial); + + // Setup the Object + fluidObj->addVisualModel(fluidVisualModel); + fluidObj->setCollidingGeometry(fluidGeometry); + fluidObj->setDynamicalModel(sphModel); + fluidObj->setPhysicsGeometry(fluidGeometry); + + return fluidObj; +} + +static std::shared_ptr<CollidingObject> +makeDragonCollidingObject(const std::string& name, const Vec3d& position) +{ + // Create the pbd object + imstkNew<CollidingObject> collidingObj(name); + + // Setup the Geometry (read dragon mesh) + auto dragonSurfMesh = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/asianDragon/asianDragon.obj"); + dragonSurfMesh->translate(position, Geometry::TransformType::ApplyToData); + + imstkNew<SurfaceMeshDistanceTransform> computeSdf; + computeSdf->setInputMesh(dragonSurfMesh); + computeSdf->setDimensions(100, 100, 100); + computeSdf->update(); + + // Setup the VisualModel + imstkNew<RenderMaterial> material; + material->setDisplayMode(RenderMaterial::DisplayMode::Surface); + imstkNew<VisualModel> surfMeshModel(dragonSurfMesh); + surfMeshModel->setRenderMaterial(material); + + // Setup the Object + collidingObj->addVisualModel(surfMeshModel); + collidingObj->setCollidingGeometry(std::make_shared<SignedDistanceField>(computeSdf->getOutputImage())); + + return collidingObj; +} + +/// +/// \brief This example demonstrates interaction between sph fluid and a +/// colliding object using signed distance fields (SDFs) +/// +int +main() +{ + // Write log to stdout and file + Logger::startLogger(); + + // Setup the scene + imstkNew<Scene> scene("SPH-Obj-SDFInteraction"); + { + //scene->getConfig()->taskTimingEnabled = true; + scene->getActiveCamera()->setPosition(0, 2.0, 15.0); + + // Static Dragon object + std::shared_ptr<CollidingObject> dragonObj = makeDragonCollidingObject("Dragon", Vec3d(0.0, 0.0, 0.0)); + scene->addSceneObject(dragonObj); + + // SPH fluid box overtop the dragon + std::shared_ptr<SPHObject> sphFluidBox = makeSPHBoxObject("Box", 0.1, Vec3d(0.0, 7.0, 0.0), Vec3d(3.0, 7.0, 3.0)); + scene->addSceneObject(sphFluidBox); + + // Interaction + imstkNew<SphObjectCollisionPair> interaction(sphFluidBox, dragonObj); + scene->getCollisionGraph()->addInteraction(interaction); + + // Light + imstkNew<DirectionalLight> light("light"); + light->setDirection(0.0, -1.0, -1.0); + light->setIntensity(1); + scene->addLight(light); + } + + // Run the simulation + { + // Setup a viewer to render in its own thread + imstkNew<VTKViewer> viewer("Viewer 1"); + viewer->setActiveScene(scene); + viewer->setBackgroundColors(Vec3d(0.3285, 0.3285, 0.6525), Vec3d(0.13836, 0.13836, 0.2748), true); + + // Setup a scene manager to advance the scene in its own thread + imstkNew<SceneManager> sceneManager("Scene Manager 1"); + sceneManager->setActiveScene(scene); + viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer + + // Add mouse and keyboard controls to the viewer + { + imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice()); + mouseControl->setSceneManager(sceneManager); + viewer->addControl(mouseControl); + + imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice()); + keyControl->setSceneManager(sceneManager); + keyControl->setViewer(viewer); + viewer->addControl(keyControl); + } + + // Start viewer running, scene as paused + sceneManager->requestStatus(ThreadStatus::Paused); + viewer->start(); + } + + return 0; +} diff --git a/Examples/Levelset/CMakeLists.txt b/Examples/Levelset/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..a7946cdf0d877d81e2967511b4feb209c88e981b --- /dev/null +++ b/Examples/Levelset/CMakeLists.txt @@ -0,0 +1,34 @@ +########################################################################### +# +# Copyright (c) Kitware, Inc. +# +# 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. +# +########################################################################### + +project(Example-Levelset) + +#----------------------------------------------------------------------------- +# Create executable +#----------------------------------------------------------------------------- +imstk_add_executable(${PROJECT_NAME} levelsetExample.cpp) + +#----------------------------------------------------------------------------- +# Add the target to Examples folder +#----------------------------------------------------------------------------- +SET_TARGET_PROPERTIES (${PROJECT_NAME} PROPERTIES FOLDER Examples) + +#----------------------------------------------------------------------------- +# Link libraries to executable +#----------------------------------------------------------------------------- +target_link_libraries(${PROJECT_NAME} SimulationManager Filtering) diff --git a/Examples/Levelset/levelsetExample.cpp b/Examples/Levelset/levelsetExample.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1d9fbfbdbb13e0d7dd5267b3c7b9a7496a81084c --- /dev/null +++ b/Examples/Levelset/levelsetExample.cpp @@ -0,0 +1,158 @@ +/*========================================================================= + + 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 "imstkCamera.h" +#include "imstkCube.h" +#include "imstkImageData.h" +#include "imstkImplicitGeometryToImageData.h" +#include "imstkKeyboardSceneControl.h" +#include "imstkLevelSetDeformableObject.h" +#include "imstkLevelSetModel.h" +#include "imstkLight.h" +#include "imstkLogger.h" +#include "imstkMeshIO.h" +#include "imstkMouseSceneControl.h" +#include "imstkNew.h" +#include "imstkPlane.h" +#include "imstkRenderMaterial.h" +#include "imstkScene.h" +#include "imstkSceneManager.h" +#include "imstkSphere.h" +#include "imstkSurfaceMesh.h" +#include "imstkSurfaceMeshDistanceTransform.h" +#include "imstkVisualModel.h" +#include "imstkVolumeRenderMaterial.h" +#include "imstkVTKViewer.h" + +#include <vtkColorTransferFunction.h> +#include <vtkPiecewiseFunction.h> +#include <vtkVolumeProperty.h> + +using namespace imstk; + +/// +/// \brief Creates a shrinking level set dragon +/// +std::shared_ptr<LevelSetDeformableObject> +makeLevelsetObj(const std::string& name) +{ + imstkNew<LevelSetDeformableObject> levelsetObj(name); + + // Setup the Geometry (read dragon mesh) + auto dragonSurfMesh = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/asianDragon/asianDragon.obj"); + //dragonSurfMesh->translate(position, Geometry::TransformType::ApplyToData); + imstkNew<SurfaceMeshDistanceTransform> computeSdf; + computeSdf->setInputMesh(dragonSurfMesh); + computeSdf->setDimensions(50, 50, 50); + computeSdf->update(); + std::shared_ptr<ImageData> initLvlsetImage = computeSdf->getOutputImage(); + + // Setup the Parameters + imstkNew<LevelSetModelConfig> lvlsetConfig; + lvlsetConfig->m_sparseUpdate = false; + lvlsetConfig->m_dt = 0.0003; + lvlsetConfig->m_constantVelocity = -6.0; + + // Setup the Model + imstkNew<LevelSetModel> dynamicalModel; + dynamicalModel->setModelGeometry(initLvlsetImage); + dynamicalModel->configure(lvlsetConfig); + + // Setup the VisualModel + imstkNew<VisualModel> visualModel(initLvlsetImage); + imstkNew<VolumeRenderMaterial> mat; + { + vtkNew<vtkColorTransferFunction> color; + color->AddRGBPoint(0.0, 1.0, 0.0, 0.0); + color->AddRGBPoint(-0.01, 0.0, 0.0, 1.0); + mat->getVolumeProperty()->SetColor(color); + vtkNew<vtkPiecewiseFunction> opacity; + opacity->AddPoint(0.0, 0.0); + opacity->AddPoint(-0.01, 1.0); + mat->getVolumeProperty()->SetScalarOpacity(opacity); + mat->getVolumeProperty()->SetInterpolationTypeToLinear(); + mat->getVolumeProperty()->ShadeOn(); + } + visualModel->setRenderMaterial(mat); + + // Setup the Object + levelsetObj->addVisualModel(visualModel); + levelsetObj->setPhysicsGeometry(initLvlsetImage); + levelsetObj->setDynamicalModel(dynamicalModel); + + return levelsetObj; +} + +/// +/// \brief This example demonstrates evolution of a levelset +/// +int +main() +{ + // Log to file and stdout + Logger::startLogger(); + + // Setup the scene + imstkNew<Scene> scene("Levelset"); + { + std::shared_ptr<LevelSetDeformableObject> obj = makeLevelsetObj("DragonLevelset"); + scene->addSceneObject(obj); + + // Light (white) + imstkNew<DirectionalLight> whiteLight("whiteLight"); + whiteLight->setFocalPoint(Vec3d(5.0, -8.0, -5.0)); + whiteLight->setIntensity(1.0); + scene->addLight(whiteLight); + + // Adjust camera + scene->getActiveCamera()->setPosition(0.0, 10.0, -10.0); + } + + // Run the simulation + { + // Setup a viewer to render in its own thread + imstkNew<VTKViewer> viewer("Viewer"); + viewer->setActiveScene(scene); + + // Setup a scene manager to advance the scene in its own thread + imstkNew<SceneManager> sceneManager("Scene Manager"); + sceneManager->setActiveScene(scene); + viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer + + // Add mouse and keyboard controls to the viewer + { + imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice()); + mouseControl->setSceneManager(sceneManager); + viewer->addControl(mouseControl); + + imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice()); + keyControl->setSceneManager(sceneManager); + keyControl->setViewer(viewer); + viewer->addControl(keyControl); + } + + // Start viewer running, scene as paused + sceneManager->requestStatus(ThreadStatus::Paused); + viewer->start(); + } + + return 0; +} diff --git a/Examples/MeshIO/CMakeLists.txt b/Examples/MeshIO/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..f749003dfa0637975632636f6325c54cf60e49c1 --- /dev/null +++ b/Examples/MeshIO/CMakeLists.txt @@ -0,0 +1,19 @@ +#----------------------------------------------------------------------------- +# Add Example subdirectories +#----------------------------------------------------------------------------- +macro(listOfSubDir result curdir) + file(GLOB children RELATIVE ${curdir} ${curdir}/*) + set(dirlist "") + foreach(child ${children}) + if(IS_DIRECTORY ${curdir}/${child}) + list(APPEND dirlist ${child}) + endif() + endforeach() + set(${result} ${dirlist}) +endmacro() + +listOfSubDir(subDirs ${CMAKE_CURRENT_SOURCE_DIR}) + +foreach(subdir ${subDirs}) + add_subdirectory(${subdir}) +endforeach() diff --git a/Examples/MeshIO/ConvertVTKToVega/CMakeLists.txt b/Examples/MeshIO/ConvertVTKToVega/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..8c7b89cb5167089d4e3dcad7961a7fe657169974 --- /dev/null +++ b/Examples/MeshIO/ConvertVTKToVega/CMakeLists.txt @@ -0,0 +1,34 @@ +########################################################################### +# +# Copyright (c) Kitware, Inc. +# +# 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. +# +########################################################################### + +project(Example-ConvertVTKToVega) + +#----------------------------------------------------------------------------- +# Create executable +#----------------------------------------------------------------------------- +imstk_add_executable(${PROJECT_NAME} ConvertVTKToVega.cpp) + +#----------------------------------------------------------------------------- +# Add the target to Examples folder +#----------------------------------------------------------------------------- +SET_TARGET_PROPERTIES (${PROJECT_NAME} PROPERTIES FOLDER Examples/MeshIO) + +#----------------------------------------------------------------------------- +# Link libraries to executable +#----------------------------------------------------------------------------- +target_link_libraries(${PROJECT_NAME} MeshIO) diff --git a/Examples/MeshIO/ConvertVTKToVega/ConvertVTKToVega.cpp b/Examples/MeshIO/ConvertVTKToVega/ConvertVTKToVega.cpp new file mode 100644 index 0000000000000000000000000000000000000000..056c64db511ace4364dbedb82422601a0ac4e941 --- /dev/null +++ b/Examples/MeshIO/ConvertVTKToVega/ConvertVTKToVega.cpp @@ -0,0 +1,57 @@ +/*========================================================================= + + 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 "imstkMeshIO.h" +#include "imstkVegaMeshIO.h" +#include "imstkVTKMeshIO.h" +#include "imstkTetrahedralMesh.h" + +#include <string> + +using namespace imstk; + +const std::string defaultFileName = iMSTK_DATA_ROOT "textured_organs/heart_volume.vtk"; + +int +main(int argc, char** argv) +{ + std::string vtkFileName = defaultFileName; + std::string vegaFileName = "convertedMesh.veg"; + + if (argc > 1) + { + vtkFileName = std::string(argv[1]); + } + + auto tetMesh = MeshIO::read<TetrahedralMesh>(vtkFileName); + tetMesh->rotate(Vec3d(1.0, 0.0, 0.0), -1.3, Geometry::TransformType::ApplyToData); + bool converted = VegaMeshIO::write(tetMesh, vegaFileName, MeshFileType::VEG); + { + std::string vtkFileName = "convertedMesh.vtk"; + bool converted = VTKMeshIO::write(tetMesh, vtkFileName, MeshFileType::VTK); + } + + if (converted) + { + return 0; + } + return 1; +} diff --git a/Examples/MultipleScenes/multipleScenes.cpp b/Examples/MultipleScenes/multipleScenes.cpp index 8b5cd383bc0ab66fc08555a8da941cc08f20ffaf..c8fa6658955cf303e585e802b2e2c1b8d376f4d0 100644 --- a/Examples/MultipleScenes/multipleScenes.cpp +++ b/Examples/MultipleScenes/multipleScenes.cpp @@ -19,50 +19,160 @@ =========================================================================*/ -#include "imstkSimulationManager.h" -#include "imstkPbdModel.h" -#include "imstkPbdObject.h" #include "imstkAPIUtilities.h" -#include "imstkOneToOneMap.h" #include "imstkCamera.h" -#include "imstkSurfaceMesh.h" +#include "imstkConsoleThread.h" +#include "imstkKeyboardDeviceClient.h" +#include "imstkLogger.h" #include "imstkMeshIO.h" -#include "imstkTetrahedralMesh.h" +#include "imstkNew.h" +#include "imstkOneToOneMap.h" +#include "imstkPbdModel.h" +#include "imstkPbdObject.h" #include "imstkPlane.h" +#include "imstkRenderMaterial.h" #include "imstkScene.h" +#include "imstkSceneManager.h" +#include "imstkSurfaceMesh.h" +#include "imstkTetrahedralMesh.h" +#include "imstkViewer.h" +#include "imstkVisualModel.h" +#include "imstkVTKViewer.h" +#include "imstkLight.h" using namespace imstk; +/// +/// \brief Creates cloth geometry +/// +static std::shared_ptr<SurfaceMesh> +makeClothGeometry(const double width, + const double height, + const int nRows, + const int nCols) +{ + imstkNew<SurfaceMesh> clothMesh; + + StdVectorOfVec3d vertList; + vertList.resize(nRows * nCols); + const double dy = width / (double)(nCols - 1); + const double dx = height / (double)(nRows - 1); + for (int i = 0; i < nRows; ++i) + { + for (int j = 0; j < nCols; j++) + { + vertList[i * nCols + j] = Vec3d((double)dx * i, 1.0, (double)dy * j); + } + } + clothMesh->setInitialVertexPositions(vertList); + clothMesh->setVertexPositions(vertList); + + // Add connectivity data + std::vector<SurfaceMesh::TriangleArray> triangles; + for (std::size_t i = 0; i < nRows - 1; ++i) + { + for (std::size_t j = 0; j < nCols - 1; j++) + { + SurfaceMesh::TriangleArray tri[2]; + const size_t index1 = i * nCols + j; + const size_t index2 = index1 + nCols; + const size_t index3 = index1 + 1; + const size_t index4 = index2 + 1; + + // Interleave [/][\] + if (i % 2 ^ j % 2) + { + tri[0] = { { index1, index2, index3 } }; + tri[1] = { { index4, index3, index2 } }; + } + else + { + tri[0] = { { index2, index4, index1 } }; + tri[1] = { { index4, index3, index1 } }; + } + triangles.push_back(tri[0]); + triangles.push_back(tri[1]); + } + } + + clothMesh->setTrianglesVertices(triangles); + + return clothMesh; +} + +/// +/// \brief Creates cloth object +/// +static std::shared_ptr<PbdObject> +makeClothObj(const std::string& name, + const double width, + const double height, + const int nRows, + const int nCols) +{ + imstkNew<PbdObject> clothObj(name); + + // Setup the Geometry + std::shared_ptr<SurfaceMesh> clothMesh(makeClothGeometry(width, height, nRows, nCols)); + + // Setup the Parameters + imstkNew<PBDModelConfig> pbdParams; + pbdParams->enableConstraint(PbdConstraint::Type::Distance, 1.0e2); + pbdParams->enableConstraint(PbdConstraint::Type::Dihedral, 1.0e1); + pbdParams->m_fixedNodeIds = { 0, static_cast<size_t>(nCols) - 1 }; + pbdParams->m_uniformMassValue = width * height / ((double)nRows * (double)nCols); + pbdParams->m_gravity = Vec3d(0.0, -9.8, 0.0); + pbdParams->m_defaultDt = 0.005; + pbdParams->m_iterations = 5; + + // Setup the Model + imstkNew<PbdModel> pbdModel; + pbdModel->setModelGeometry(clothMesh); + pbdModel->configure(pbdParams); + + // Setup the VisualModel + imstkNew<RenderMaterial> material; + material->setBackFaceCulling(false); + material->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface); + + imstkNew<VisualModel> visualModel(clothMesh); + visualModel->setRenderMaterial(material); + + // Setup the Object + clothObj->addVisualModel(visualModel); + clothObj->setPhysicsGeometry(clothMesh); + clothObj->setDynamicalModel(pbdModel); + + return clothObj; +} + std::shared_ptr<Scene> -createSoftBodyScene(std::shared_ptr<SimulationManager> simManager, const char* sceneName) +createSoftBodyScene(std::string sceneName) { - auto sceneConfig = std::make_shared<SceneConfig>(); + imstkNew<SceneConfig> sceneConfig; sceneConfig->lazyInitialization = true; - auto scene = simManager->createNewScene(sceneName, sceneConfig); - scene->getCamera()->setPosition(0, 2.0, 15.0); + imstkNew<Scene> scene(sceneName, sceneConfig); + + scene->getActiveCamera()->setPosition(0.0, 2.0, 15.0); // Load a sample mesh - auto tetMesh = MeshIO::read(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg"); + auto tetMesh = MeshIO::read<TetrahedralMesh>(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg"); // Extract the surface mesh - auto surfMesh = std::make_shared<SurfaceMesh>(); - auto volTetMesh = std::dynamic_pointer_cast<TetrahedralMesh>(tetMesh); - volTetMesh->extractSurfaceMesh(surfMesh, true); + imstkNew<SurfaceMesh> surfMesh; + tetMesh->extractSurfaceMesh(surfMesh, true); - auto material = std::make_shared<RenderMaterial>(); + imstkNew<RenderMaterial> material; material->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface); - auto surfMeshModel = std::make_shared<VisualModel>(surfMesh); + imstkNew<VisualModel> surfMeshModel(surfMesh.get()); surfMeshModel->setRenderMaterial(material); - // Construct one to one nodal map based on the above meshes - auto oneToOneNodalMap = std::make_shared<OneToOneMap>(tetMesh, surfMesh); - - auto deformableObj = std::make_shared<PbdObject>("Dragon"); - auto pbdModel = std::make_shared<PbdModel>(); - pbdModel->setModelGeometry(volTetMesh); + imstkNew<PbdObject> deformableObj("Dragon"); + imstkNew<PbdModel> pbdModel; + pbdModel->setModelGeometry(tetMesh); // configure model - auto pbdParams = std::make_shared<PBDModelConfig>(); + imstkNew<PBDModelConfig> pbdParams; // FEM constraint pbdParams->m_femParams->m_YoungModulus = 100.0; @@ -72,27 +182,23 @@ createSoftBodyScene(std::shared_ptr<SimulationManager> simManager, const char* s // Other parameters pbdParams->m_uniformMassValue = 1.0; - pbdParams->m_gravity = Vec3d(0, -9.8, 0); + pbdParams->m_gravity = Vec3d(0.0, -9.8, 0.0); pbdParams->m_iterations = 45; // Set the parameters pbdModel->configure(pbdParams); deformableObj->setDynamicalModel(pbdModel); deformableObj->addVisualModel(surfMeshModel); - deformableObj->setPhysicsGeometry(volTetMesh); - deformableObj->setPhysicsToVisualMap(oneToOneNodalMap); //assign the computed map - + deformableObj->setPhysicsGeometry(tetMesh); + deformableObj->setPhysicsToVisualMap(std::make_shared<OneToOneMap>(tetMesh, surfMesh)); deformableObj->setDynamicalModel(pbdModel); - /*auto pbdSolver = std::make_shared<PbdSolver>(); - pbdSolver->setPbdObject(deformableObj); - scene->addNonlinearSolver(pbdSolver);*/ scene->addSceneObject(deformableObj); - auto planeGeom = std::make_shared<Plane>(); - planeGeom->setWidth(40); + imstkNew<Plane> planeGeom; + planeGeom->setWidth(40.0); planeGeom->setTranslation(0, -6, 0); - auto planeObj = std::make_shared<CollidingObject>("Plane"); + imstkNew<CollidingObject> planeObj("Plane"); planeObj->setVisualGeometry(planeGeom); planeObj->setCollidingGeometry(planeGeom); scene->addSceneObject(planeObj); @@ -101,140 +207,79 @@ createSoftBodyScene(std::shared_ptr<SimulationManager> simManager, const char* s } std::shared_ptr<Scene> -createClothScene(std::shared_ptr<SimulationManager> simManager, const char* sceneName) +createClothScene(std::string sceneName) { - auto sceneConfig = std::make_shared<SceneConfig>(); - sceneConfig->lazyInitialization = true; - auto scene = simManager->createNewScene(sceneName, sceneConfig); - - // Create surface mesh - auto surfMesh = std::make_shared<SurfaceMesh>(); - StdVectorOfVec3d vertList; - const double width = 10.0; - const double height = 10.0; - const int nRows = 11; - const int nCols = 11; - vertList.resize(nRows * nCols); - const double dy = width / (double)(nCols - 1); - const double dx = height / (double)(nRows - 1); - for (int i = 0; i < nRows; ++i) + imstkNew<Scene> scene("PBDCloth"); { - for (int j = 0; j < nCols; j++) - { - vertList[i * nCols + j] = Vec3d((double)dx * i, 1.0, (double)dy * j); - } + std::shared_ptr<PbdObject> clothObj = makeClothObj("Cloth", 10.0, 10.0, 16, 16); + scene->addSceneObject(clothObj); + + // Light (white) + imstkNew<DirectionalLight> whiteLight("whiteLight"); + whiteLight->setFocalPoint(Vec3d(5.0, -8.0, -5.0)); + whiteLight->setIntensity(1.0); + scene->addLight(whiteLight); + + // Light (red) + imstkNew<SpotLight> colorLight("colorLight"); + colorLight->setPosition(Vec3d(-5.0, -3.0, 5.0)); + colorLight->setFocalPoint(Vec3d(0.0, -5.0, 5.0)); + colorLight->setIntensity(100.); + colorLight->setColor(Color::Red); + colorLight->setSpotAngle(30.0); + scene->addLight(colorLight); + + // Adjust camera + scene->getActiveCamera()->setFocalPoint(0.0, -5.0, 5.0); + scene->getActiveCamera()->setPosition(-15.0, -5.0, 25.0); + scene->getActiveCamera()->setPosition(-15., -5.0, 15.0); } - surfMesh->setInitialVertexPositions(vertList); - surfMesh->setVertexPositions(vertList); - - // Add connectivity data - std::vector<SurfaceMesh::TriangleArray> triangles; - for (std::size_t i = 0; i < nRows - 1; ++i) - { - for (std::size_t j = 0; j < nCols - 1; j++) - { - SurfaceMesh::TriangleArray tri[2]; - tri[0] = { { i* nCols + j, (i + 1) * nCols + j, i* nCols + j + 1 } }; - tri[1] = { { (i + 1) * nCols + j + 1, i* nCols + j + 1, (i + 1) * nCols + j } }; - triangles.push_back(tri[0]); - triangles.push_back(tri[1]); - } - } - - surfMesh->setTrianglesVertices(triangles); - - // Create Object & Model - auto deformableObj = std::make_shared<PbdObject>("Cloth"); - auto pbdModel = std::make_shared<PbdModel>(); - pbdModel->setModelGeometry(surfMesh); - - // configure model - auto pbdParams = std::make_shared<PBDModelConfig>(); - - // Constraints - pbdParams->enableConstraint(PbdConstraint::Type::Distance, 0.1); - pbdParams->enableConstraint(PbdConstraint::Type::Dihedral, 0.001); - std::vector<size_t> fixedNodes(nCols); - for (size_t i = 0; i < fixedNodes.size(); i++) - { - fixedNodes[i] = i; - } - pbdParams->m_fixedNodeIds = fixedNodes; - - // Other parameters - pbdParams->m_uniformMassValue = 1.0; - pbdParams->m_gravity = Vec3d(0, -9.8, 0); - pbdParams->m_defaultDt = 0.03; - pbdParams->m_iterations = 5; - - // Set the parameters - pbdModel->configure(pbdParams); - deformableObj->setDynamicalModel(pbdModel); - deformableObj->setPhysicsGeometry(surfMesh); - - auto material = std::make_shared<RenderMaterial>(); - material->setBackFaceCulling(false); - material->setColor(Color::LightGray); - material->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface); - auto surfMeshModel = std::make_shared<VisualModel>(surfMesh); - surfMeshModel->setRenderMaterial(material); - deformableObj->addVisualModel(surfMeshModel); - - // Solver - - scene->addSceneObject(deformableObj); - - scene->getCamera()->setFocalPoint(0, -5, 5); - scene->getCamera()->setPosition(-15., -5.0, 15.0); - return scene; } void testMultipleScenesInBackendMode() { - auto simConfig = std::make_shared<SimManagerConfig>(); - simConfig->simulationMode = SimulationMode::Backend; - auto simManager = std::make_shared<SimulationManager>(simConfig); + imstkNew<SceneManager> sceneManager("SceneManager"); + auto scene1 = createClothScene("clothScene"); + sceneManager->addScene(scene1); + auto scene2 = createSoftBodyScene("deformableBodyScene"); + sceneManager->addScene(scene2); - auto scene1 = createClothScene(simManager, "clothScene"); - auto scene2 = createSoftBodyScene(simManager, "deformableBodyScene"); + scene1->initialize(); + scene2->initialize(); // set to scene 1 - simManager->setActiveScene(scene1); + sceneManager->setActiveScene(scene1); - simManager->initialize(); - - simManager->advanceFrame(); - simManager->advanceFrame(); - simManager->advanceFrame(); - simManager->advanceFrame(); + sceneManager->update(); + sceneManager->update(); + sceneManager->update(); + sceneManager->update(); // set to scene 2 - simManager->setActiveScene(scene2); + sceneManager->setActiveScene(scene2); - simManager->advanceFrame(); - simManager->advanceFrame(); - simManager->advanceFrame(); - simManager->advanceFrame(); + sceneManager->update(); + sceneManager->update(); + sceneManager->update(); + sceneManager->update(); // set to scene 1 - simManager->setActiveScene(scene1); + sceneManager->setActiveScene(scene1); - simManager->advanceFrame(); - simManager->advanceFrame(); - simManager->advanceFrame(); - simManager->advanceFrame(); + sceneManager->update(); + sceneManager->update(); + sceneManager->update(); + sceneManager->update(); // set to scene 2 - simManager->setActiveScene(scene2); - - simManager->advanceFrame(); - simManager->advanceFrame(); - simManager->advanceFrame(); - simManager->advanceFrame(); + sceneManager->setActiveScene(scene2); - simManager->end(); + sceneManager->update(); + sceneManager->update(); + sceneManager->update(); + sceneManager->update(); std::cout << "Press any key to exit..." << std::endl; @@ -245,75 +290,109 @@ void testMultipleScenesInRenderMode() { // Simulation manager defaults to rendering mode - auto simManager = std::make_shared<SimulationManager>(); - auto scene1 = createClothScene(simManager, "clothScene"); - auto scene2 = createSoftBodyScene(simManager, "deformableBodyScene"); + auto scene1 = createClothScene("clothScene"); + auto scene2 = createSoftBodyScene("deformableBodyScene"); scene1->getConfig()->trackFPS = true; + scene1->initialize(); + scene2->initialize(); + // set to scene 1 - simManager->setActiveScene(scene2); + imstkNew<SceneManager> sceneManager("SceneManager"); + sceneManager->setActiveScene(scene2); + + // Setup a viewer to render in its own thread + imstkNew<VTKViewer> viewer("Viewer"); + viewer->setActiveScene(scene2); + viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer // Create a call back on key press of 's' to switch scenes - auto viewer = simManager->getViewer(); - if (viewer) - { - std::cout << "Press 's/S' to switch scenes" << std::endl; + LOG(INFO) << "s/S followed by enter to switch scenes"; + LOG(INFO) << "q/Q followed by enter to quit"; - viewer->setOnCharFunction('s', [&](InteractorStyle* c) -> bool + connect<KeyPressEvent>(viewer->getKeyboardDevice(), EventType::KeyPress, + [&](KeyPressEvent* e) + { + if (e->m_keyPressType == KEY_PRESS) { - if (simManager->getActiveScene() == scene1) + if (e->m_key == 's' || e->m_key == 'S') { - simManager->setActiveScene(scene2); + if (sceneManager->getActiveScene() == scene1) + { + sceneManager->setActiveScene(scene2); + viewer->setActiveScene(scene2); + } + else + { + sceneManager->setActiveScene(scene1); + viewer->setActiveScene(scene1); + } + + if (!sceneManager->getActiveScene()) + { + sceneManager->setActiveScene(scene1); + viewer->setActiveScene(scene1); + } } - else - { - simManager->setActiveScene(scene1); - } - - if (!simManager->getActiveScene()) + else if (e->m_key == 'q' || e->m_key == 'Q') { - simManager->setActiveScene(scene1); + viewer->stop(false); } - - return true; + } }); - } if (scene1->getConfig()->trackFPS) { - apiutils::printUPS(simManager->getSceneManager(scene1)); + apiutils::printUPS(sceneManager); } - simManager->start(); + viewer->start(); } void testMultipleScenesInBackgroundMode() { - auto simConfig = std::make_shared<SimManagerConfig>(); - simConfig->simulationMode = SimulationMode::RunInBackgroundSync; - auto simManager = std::make_shared<SimulationManager>(simConfig); - auto scene1 = createClothScene(simManager, "clothScene"); - auto scene2 = createSoftBodyScene(simManager, "deformableBodyScene"); + imstkNew<ConsoleThread> consoleThread; + + imstkNew<SceneManager> sceneManager("SceneManager"); + consoleThread->addChildThread(sceneManager); // Start/stop scene with console + auto scene1 = createClothScene("clothScene"); + auto scene2 = createSoftBodyScene("deformableBodyScene"); + sceneManager->addScene(scene1); + sceneManager->addScene(scene2); - simManager->setActiveScene(scene1); + scene1->initialize(); + scene2->initialize(); - std::cout << "Press 's/S' to switch scenes" << std::endl; - auto keyPressFunc = [&]() + sceneManager->setActiveScene(scene1); + + LOG(INFO) << "s/S followed by enter to switch scenes"; + LOG(INFO) << "q/Q followed by enter to quit"; + auto keyPressFunc = [&](KeyPressEvent* e) { - if (simManager->getActiveScene()->getName() == scene1->getName()) - { - simManager->setActiveScene(scene2); - } - else + if (e->m_keyPressType == KEY_PRESS) { - simManager->setActiveScene(scene1); + if (e->m_key == 's' || e->m_key == 'S') + { + if (sceneManager->getActiveScene()->getName() == scene1->getName()) + { + sceneManager->setActiveScene(scene2); + } + else + { + sceneManager->setActiveScene(scene1); + } + } + else if (e->m_key == 'q' || e->m_key == 'Q') + { + consoleThread->stop(false); + } } }; - simManager->addKeyPressCallback(keyPressFunc, 's'); + connect<KeyPressEvent>(consoleThread->getKeyboardDevice(), EventType::KeyPress, keyPressFunc); - simManager->start(); + consoleThread->start(); } /// @@ -322,6 +401,9 @@ testMultipleScenesInBackgroundMode() int main() { + // Setup logger (write to file and stdout) + Logger::startLogger(); + testMultipleScenesInBackendMode(); testMultipleScenesInBackgroundMode(); testMultipleScenesInRenderMode(); diff --git a/Examples/NonlinearSolver/nonlinearSolver.cpp b/Examples/NonlinearSolver/nonlinearSolver.cpp index c8a94e2490573e1be1cc9490b0f078e1ae108513..71c250804749bfb6336dd526348d4fc41a32c4d0 100644 --- a/Examples/NonlinearSolver/nonlinearSolver.cpp +++ b/Examples/NonlinearSolver/nonlinearSolver.cpp @@ -19,16 +19,14 @@ =========================================================================*/ +#include "imstkDirectLinearSolver.h" +#include "imstkNew.h" +#include "imstkNewtonSolver.h" + #include <ios> #include <iostream> -#include <vector> #include <iomanip> -#include "imstkMath.h" -#include "imstkNewtonSolver.h" -#include "imstkDirectLinearSolver.h" -#include "imstkNonLinearSolver.h" - using namespace imstk; /// @@ -74,13 +72,13 @@ main(int argc, char** argv) auto updateXold = [](void) {}; - auto nlSystem = std::make_shared<NonLinearSystem<Matrixd>>(func, jac); + imstkNew<NonLinearSystem<Matrixd>> nlSystem(func, jac); nlSystem->setUnknownVector(x); nlSystem->setUpdateFunction(updateX); nlSystem->setUpdatePreviousStatesFunction(updateXold); - auto linSolver = std::make_shared<DirectLinearSolver<Matrixd>>(); - auto nlSolver = std::make_shared<NewtonSolver<Matrixd>>(); + imstkNew<DirectLinearSolver<Matrixd>> linSolver; + imstkNew<NewtonSolver<Matrixd>> nlSolver; nlSolver->setMaxIterations(100); nlSolver->setRelativeTolerance(1e-8); nlSolver->setAbsoluteTolerance(1e-10); diff --git a/Examples/ObjectController/ObjectControllerExample.cpp b/Examples/ObjectController/ObjectControllerExample.cpp index 1cc14e4dc36e8ab428d52425ac19be0e7d9fcf62..5d17119b8ac7785fe616a4625fdd22139ba7fdd0 100644 --- a/Examples/ObjectController/ObjectControllerExample.cpp +++ b/Examples/ObjectController/ObjectControllerExample.cpp @@ -19,20 +19,23 @@ =========================================================================*/ -#include "imstkSimulationManager.h" -#include "imstkCube.h" #include "imstkCamera.h" -#include "imstkLight.h" #include "imstkCollidingObject.h" -#include "imstkHDAPIDeviceClient.h" -#include "imstkHDAPIDeviceServer.h" -#include "imstkSceneObjectController.h" -#include "imstkCollisionGraph.h" -#include "imstkDeviceTracker.h" +#include "imstkCube.h" +#include "imstkHapticDeviceClient.h" +#include "imstkHapticDeviceManager.h" +#include "imstkKeyboardSceneControl.h" +#include "imstkLight.h" +#include "imstkLogger.h" +#include "imstkMouseSceneControl.h" +#include "imstkNew.h" #include "imstkScene.h" +#include "imstkSceneManager.h" +#include "imstkSceneObjectController.h" +#include "imstkVTKViewer.h" // global variables -const std::string phantomOmni1Name = "Phantom1"; +const std::string phantomOmni1Name = "Default Device"; using namespace imstk; @@ -43,48 +46,65 @@ using namespace imstk; int main() { -#ifdef iMSTK_USE_OPENHAPTICS - // simManager and Scene - auto simManager = std::make_shared<SimulationManager>(); - auto scene = simManager->createNewScene("ObjectController"); + // Setup logger (write to file and stdout) + Logger::startLogger(); - // Device Client - auto client = std::make_shared<HDAPIDeviceClient>(phantomOmni1Name); + // Create Scene + imstkNew<Scene> scene("ObjectController"); // Device Server - auto server = std::make_shared<HDAPIDeviceServer>(); - server->addDeviceClient(client); - simManager->addModule(server); + imstkNew<HapticDeviceManager> server; + std::shared_ptr<HapticDeviceClient> client = server->makeDeviceClient(phantomOmni1Name); // Object - auto geom = std::make_shared<Cube>(); - geom->setPosition(0, 1, 0); - geom->setWidth(2); - - auto object = std::make_shared<CollidingObject>("VirtualObject"); + imstkNew<Cube> geom(Vec3d(0.0, 1.0, 0.0), 2.0); + imstkNew<CollidingObject> object("VirtualObject"); object->setVisualGeometry(geom); object->setCollidingGeometry(geom); scene->addSceneObject(object); - auto trackCtrl = std::make_shared<DeviceTracker>(client); - trackCtrl->setTranslationScaling(0.1); - auto controller = std::make_shared<SceneObjectController>(object, trackCtrl); - scene->addObjectController(controller); + imstkNew<SceneObjectController> controller(object, client); + controller->setTranslationScaling(0.1); + scene->addController(controller); // Update Camera position - auto cam = scene->getCamera(); - cam->setPosition(Vec3d(0, 0, 10)); + std::shared_ptr<Camera> cam = scene->getActiveCamera(); + cam->setPosition(Vec3d(0.0, 0.0, 10.0)); cam->setFocalPoint(geom->getPosition()); // Light - auto light = std::make_shared<DirectionalLight>("light"); - light->setFocalPoint(Vec3d(5, -8, -5)); - light->setIntensity(1); + imstkNew<DirectionalLight> light("light"); + light->setFocalPoint(Vec3d(5.0, -8.0, -5.0)); + light->setIntensity(1.0); scene->addLight(light); - // Run - simManager->setActiveScene(scene); - simManager->start(); -#endif + //Run the simulation + { + // Setup a viewer to render in its own thread + imstkNew<VTKViewer> viewer("Viewer 1"); + viewer->setActiveScene(scene); + + // Setup a scene manager to advance the scene in its own thread + imstkNew<SceneManager> sceneManager("Scene Manager 1"); + sceneManager->setActiveScene(scene); + viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer + + viewer->addChildThread(server); + + // Add mouse and keyboard controls to the viewer + { + imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice()); + mouseControl->setSceneManager(sceneManager); + viewer->addControl(mouseControl); + + imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice()); + keyControl->setSceneManager(sceneManager); + keyControl->setViewer(viewer); + viewer->addControl(keyControl); + } + + // Start the viewer and its children + viewer->start(); + } return 0; } diff --git a/Examples/ObjectControllerDummyClient/ObjectCtrlDummyClientExample.cpp b/Examples/ObjectControllerDummyClient/ObjectCtrlDummyClientExample.cpp index 632019b2aaa2cf9b8f9506b6c88b0ca63c1102f5..d88f219f06a5f3624fefa059e486688421fc4db5 100644 --- a/Examples/ObjectControllerDummyClient/ObjectCtrlDummyClientExample.cpp +++ b/Examples/ObjectControllerDummyClient/ObjectCtrlDummyClientExample.cpp @@ -19,16 +19,17 @@ =========================================================================*/ -#include "imstkSimulationManager.h" -#include "imstkCollidingObject.h" #include "imstkCamera.h" -#include "imstkLight.h" -#include "imstkSceneManager.h" +#include "imstkCollidingObject.h" #include "imstkCube.h" #include "imstkDummyClient.h" -#include "imstkDeviceTracker.h" -#include "imstkSceneObjectController.h" +#include "imstkLight.h" +#include "imstkLogger.h" +#include "imstkNew.h" #include "imstkScene.h" +#include "imstkSceneManager.h" +#include "imstkSceneObjectController.h" +#include "imstkVTKViewer.h" using namespace imstk; @@ -39,31 +40,30 @@ using namespace imstk; int main() { - // simManager and Scene - auto simManager = std::make_shared<SimulationManager>(); - auto scene = simManager->createNewScene("ObjectControllerDummyClient"); + Logger::startLogger(); + + imstkNew<Scene> scene("ObjectControllerDummyClient"); // Device Client - auto client = std::make_shared<DummyClient>("DummyClient"); + imstkNew<DummyClient> client("DummyClient"); // Object - auto geom = std::make_shared<Cube>(); - geom->setPosition(0, 1, 0); - geom->setWidth(2); + imstkNew<Cube> geom; + geom->setPosition(0.0, 1.0, 0.0); + geom->setWidth(2.0); - auto object = std::make_shared<CollidingObject>("VirtualObject"); + imstkNew<CollidingObject> object("VirtualObject"); object->setVisualGeometry(geom); object->setCollidingGeometry(geom); scene->addSceneObject(object); - auto trackCtrl = std::make_shared<DeviceTracker>(client); - trackCtrl->setTranslationScaling(0.1); - auto controller = std::make_shared<SceneObjectController>(object, trackCtrl); - scene->addObjectController(controller); + imstkNew<SceneObjectController> controller(object, client); + controller->setTranslationScaling(0.1); + scene->addController(controller); // Supply translation to dummy client frame auto translateFunc = - [&client](Module* module) + [&client](Event*) { Vec3d p = client->getPosition() + Vec3d(1.0e-4, 0, 0); if (p.x() > 50.) @@ -72,22 +72,31 @@ main() } client->setPosition(p); }; - simManager->getSceneManager(scene)->setPostUpdateCallback(translateFunc); // Update Camera position - auto cam = scene->getCamera(); - cam->setPosition(Vec3d(0, 0, 10)); - cam->setFocalPoint(geom->getPosition()); + scene->getActiveCamera()->setPosition(0.0, 0.0, 10.0); + scene->getActiveCamera()->setFocalPoint(geom->getPosition()); // Light - auto light = std::make_shared<DirectionalLight>("light"); - light->setFocalPoint(Vec3d(5, -8, -5)); - light->setIntensity(1); + imstkNew<DirectionalLight> light("light"); + light->setFocalPoint(Vec3d(5.0, -8.0, -5.0)); + light->setIntensity(1.0); scene->addLight(light); - // Run - simManager->setActiveScene(scene); - simManager->start(); + // Run the simulation + { + // Setup a viewer to render in its own thread + imstkNew<VTKViewer> viewer("Viewer"); + viewer->setActiveScene(scene); + + // Setup a scene manager to advance the scene in its own thread + imstkNew<SceneManager> sceneManager("Scene Manager"); + sceneManager->setActiveScene(scene); + viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer + connect<Event>(sceneManager, EventType::PostUpdate, translateFunc); + + viewer->start(); + } return 0; } diff --git a/Examples/Octree/BunnyMesh.cpp b/Examples/Octree/BunnyMesh.cpp index 34ae07934852d15b2cb1c2e36f379fae34fd4c69..417538ef5baaaeb494c3a0daed1fc1f31086fdc9 100644 --- a/Examples/Octree/BunnyMesh.cpp +++ b/Examples/Octree/BunnyMesh.cpp @@ -23,6 +23,7 @@ #include "imstkLogger.h" #include <array> + using namespace imstk; std::pair<StdVectorOfVec3d, std::vector<std::array<size_t, 3>>> diff --git a/Examples/Octree/OctreeExample.cpp b/Examples/Octree/OctreeExample.cpp index ddc8e70b2707ae28526316c6b06719da407138b0..1899a4d622f786c9c27f9d814b7d4c7239276147 100644 --- a/Examples/Octree/OctreeExample.cpp +++ b/Examples/Octree/OctreeExample.cpp @@ -19,25 +19,26 @@ =========================================================================*/ -#include "imstkSimulationManager.h" -#include "imstkSceneObject.h" -#include "imstkDebugRenderGeometry.h" -#include "imstkAPIUtilities.h" -#include "imstkLooseOctree.h" -#include "imstkVTKViewer.h" -#include "imstkTimer.h" -#include "imstkLight.h" -#include "imstkSurfaceMesh.h" -#include "imstkSceneManager.h" #include "imstkCamera.h" -#include "imstkVTKTextStatusManager.h" -#include "imstkCollisionGraph.h" +#include "imstkKeyboardSceneControl.h" +#include "imstkLight.h" +#include "imstkLogger.h" +#include "imstkLooseOctree.h" +#include "imstkMouseSceneControl.h" +#include "imstkNew.h" +#include "imstkRenderMaterial.h" #include "imstkScene.h" +#include "imstkSceneManager.h" +#include "imstkSceneObject.h" +#include "imstkSurfaceMesh.h" +#include "imstkTimer.h" +#include "imstkVisualModel.h" +#include "imstkVTKRenderDelegate.h" #include "imstkVTKRenderer.h" +#include "imstkVTKTextStatusManager.h" +#include "imstkVTKViewer.h" -#include <thread> -#include <chrono> -#include <sstream> +#include <vtkRenderWindow.h> using namespace imstk; @@ -52,25 +53,23 @@ static std::pair<StdVectorOfVec3d, std::vector<std::array<size_t, 3>>> g_BunnyDa /// \brief Read a mesh, create a visual scene object and add to the scene /// std::shared_ptr<VisualObject> -createMeshObject(const std::shared_ptr<imstk::Scene>& scene, - const std::string& objectName, - const Color& color) +createMeshObject(const std::string& objectName, + const Color& color) { // Create a surface mesh for the bunny - auto meshObj = std::make_shared<SurfaceMesh>(); - meshObj->initialize(g_BunnyData.first, g_BunnyData.second); + imstkNew<SurfaceMesh> surfMesh; + surfMesh->initialize(g_BunnyData.first, g_BunnyData.second); // Create a visiual model - auto visualModel = std::make_shared<VisualModel>(meshObj); - auto material = std::make_shared<RenderMaterial>(); + imstkNew<VisualModel> visualModel(surfMesh.get()); + imstkNew<RenderMaterial> material; material->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface); material->setColor(color); // Wireframe color - material->setLineWidth(1); + material->setLineWidth(1.0); visualModel->setRenderMaterial(material); - auto visualObject = std::make_shared<VisualObject>(objectName); + imstkNew<VisualObject> visualObject(objectName); visualObject->addVisualModel(visualModel); - scene->addSceneObject(visualObject); return visualObject; } @@ -105,20 +104,20 @@ getRandomColor() int main() { - // simManager and Scene - auto simManager = std::make_shared<SimulationManager>(); - auto scene = simManager->createNewScene("Octree Example"); + // Setup logger (write to file and stdout) + Logger::startLogger(); + + imstkNew<Scene> scene("Octree Example"); - // Get the VTKViewer - std::shared_ptr<VTKViewer> viewer = std::make_shared<VTKViewer>(simManager.get(), false); + // Setup a viewer to render in its own thread + imstkNew<VTKViewer> viewer("Viewer"); + viewer->setActiveScene(scene); viewer->setWindowTitle("Octree Example"); viewer->getVtkRenderWindow()->SetSize(1920, 1080); - simManager->setViewer(viewer); - simManager->setActiveScene(scene); // Viewer has depedence on scene auto statusManager = viewer->getTextStatusManager(); - statusManager->setStatusFontSize(VTKTextStatusManager::Custom, 30); - statusManager->setStatusFontColor(VTKTextStatusManager::Custom, Color::Orange); + statusManager->setStatusFontSize(VTKTextStatusManager::StatusType::Custom, 30); + statusManager->setStatusFontColor(VTKTextStatusManager::StatusType::Custom, Color::Orange); // Get VTK Renderer auto renderer = std::dynamic_pointer_cast<VTKRenderer>(viewer->getActiveRenderer()); @@ -131,7 +130,8 @@ main() std::vector<std::shared_ptr<SurfaceMesh>> triMeshes; for (unsigned int i = 0; i < NUM_MESHES; ++i) { - const auto sceneObj = createMeshObject(scene, "Mesh-" + std::to_string(triMeshes.size()), getRandomColor()); + std::shared_ptr<SceneObject> sceneObj = createMeshObject("Mesh-" + std::to_string(triMeshes.size()), getRandomColor()); + scene->addSceneObject(sceneObj); triMeshes.push_back(std::dynamic_pointer_cast<SurfaceMesh>(sceneObj->getVisualGeometry())); } @@ -149,7 +149,7 @@ main() timer.start(); // Create octree - LooseOctree octree(Vec3d(0, 0, 0), 100.0, 0.125, 2.0, "TestOctree"); + LooseOctree octree(Vec3d(0.0, 0.0, 0.0), 100.0, 0.125, 2.0, "TestOctree"); // Add all meshes to the octree for (const auto& mesh: triMeshes) @@ -168,11 +168,11 @@ main() // Create debug geometry for the octree (render up to 8 levels, and render all non-empty nodes) const auto debugOctree = octree.getDebugGeometry(8, true); - const auto matDbgViz = std::make_shared<RenderMaterial>(); + imstkNew<RenderMaterial> matDbgViz; matDbgViz->setDisplayMode(RenderMaterial::DisplayMode::Wireframe); matDbgViz->setEdgeColor(Color::Green); matDbgViz->setLineWidth(1.0); - auto octreeVizDbgModel = std::make_shared<VisualModel>(debugOctree, matDbgViz); + imstkNew<VisualModel> octreeVizDbgModel(debugOctree, matDbgViz); scene->addDebugVisualModel(octreeVizDbgModel); // Data for animation @@ -203,7 +203,7 @@ main() } auto updateFunc = - [&](Module*) { + [&](Event*) { // Move objects for (size_t i = 0; i < triMeshes.size(); ++i) { @@ -249,29 +249,50 @@ main() // Pause for a while std::this_thread::sleep_for(std::chrono::milliseconds(100)); }; - simManager->getSceneManager(scene)->setPostUpdateCallback(updateFunc); // Set Camera configuration - auto cam = scene->getCamera(); + auto cam = scene->getActiveCamera(); cam->setPosition(Vec3d(0, 15, 50)); cam->setFocalPoint(Vec3d(0, 0, 0)); // Light { - auto light = std::make_shared<DirectionalLight>("Light 1"); - light->setFocalPoint(Vec3d(-1, -1, -1)); + imstkNew<DirectionalLight> light("Light 1"); + light->setFocalPoint(Vec3d(-1.0, -1.0, -1.0)); light->setIntensity(1); scene->addLight(light); } { - auto light = std::make_shared<DirectionalLight>("Light 2"); - light->setFocalPoint(Vec3d(1, -1, -1)); - light->setIntensity(1); + imstkNew<DirectionalLight> light("Light 2"); + light->setFocalPoint(Vec3d(1.0, -1.0, -1.0)); + light->setIntensity(1.0); scene->addLight(light); } - // Run - simManager->start(SimulationStatus::Paused); + // Run the simulation + { + // Setup a scene manager to advance the scene in its own thread + imstkNew<SceneManager> sceneManager("Scene Manager"); + sceneManager->setActiveScene(scene); + viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer + connect<Event>(sceneManager, EventType::PostUpdate, updateFunc); + + // Add mouse and keyboard controls to the viewer + { + imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice()); + mouseControl->setSceneManager(sceneManager); + viewer->addControl(mouseControl); + + imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice()); + keyControl->setSceneManager(sceneManager); + keyControl->setViewer(viewer); + viewer->addControl(keyControl); + } + + // Start viewer running, scene as paused + sceneManager->requestStatus(ThreadStatus::Paused); + viewer->start(); + } return 0; } diff --git a/Examples/OpenVRController/CMakeLists.txt b/Examples/OpenVRController/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..3445445c7787261bba49b67bd2e52bdae52285d7 --- /dev/null +++ b/Examples/OpenVRController/CMakeLists.txt @@ -0,0 +1,34 @@ +########################################################################### +# +# Copyright (c) Kitware, Inc. +# +# 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. +# +########################################################################### + +project(Example-OpenVRController) + +#----------------------------------------------------------------------------- +# Create executable +#----------------------------------------------------------------------------- +imstk_add_executable(${PROJECT_NAME} OpenVRControllerExample.cpp) + +#----------------------------------------------------------------------------- +# Add the target to Examples folder +#----------------------------------------------------------------------------- +SET_TARGET_PROPERTIES (${PROJECT_NAME} PROPERTIES FOLDER Examples/OpenVR) + +#----------------------------------------------------------------------------- +# Link libraries to executable +#----------------------------------------------------------------------------- +target_link_libraries(${PROJECT_NAME} SimulationManager apiUtilities) \ No newline at end of file diff --git a/Examples/OpenVRController/OpenVRControllerExample.cpp b/Examples/OpenVRController/OpenVRControllerExample.cpp new file mode 100644 index 0000000000000000000000000000000000000000..deeb899735f84b184350dbc00b94d3a63eb35bd6 --- /dev/null +++ b/Examples/OpenVRController/OpenVRControllerExample.cpp @@ -0,0 +1,199 @@ +/*========================================================================= + + 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 "imstkCamera.h" +#include "imstkLight.h" +#include "imstkLogger.h" +#include "imstkMeshIO.h" +#include "imstkNew.h" +#include "imstkOpenVRDeviceClient.h" +#include "imstkRenderMaterial.h" +#include "imstkScene.h" +#include "imstkSceneManager.h" +#include "imstkSceneObject.h" +#include "imstkSceneObjectController.h" +#include "imstkSurfaceMesh.h" +#include "imstkVisualModel.h" +#include "imstkVTKOpenVRViewer.h" + +using namespace imstk; + +std::shared_ptr<SceneObject> +makeHandleObject() +{ + imstkNew<SceneObject> scalpelHandle("ScalpelHandle"); + auto toolHandleMesh = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/Surgical Instruments/Scalpel/Scalpel_Handle.obj"); + toolHandleMesh->translate(0.0, 0.0, 1.0, Geometry::TransformType::ApplyToData); + toolHandleMesh->rotate(Vec3d(0.0, 1.0, 0.0), 3.14, Geometry::TransformType::ApplyToData); + toolHandleMesh->rotate(Vec3d(1.0, 0.0, 0.0), -1.57, Geometry::TransformType::ApplyToData); + toolHandleMesh->scale(0.06, Geometry::TransformType::ApplyToData); + + imstkNew<VisualModel> toolHandleModel(toolHandleMesh); + imstkNew<RenderMaterial> material; + material->setDisplayMode(RenderMaterial::DisplayMode::Surface); + material->setShadingModel(RenderMaterial::ShadingModel::PBR); + material->setMetalness(0.9f); + material->setRoughness(0.2f); + material->addTexture(std::make_shared<Texture>( + iMSTK_DATA_ROOT "/Surgical Instruments/Scalpel/Scalpel_Albedo.png", + Texture::Type::Diffuse)); + toolHandleModel->setRenderMaterial(material); + + scalpelHandle->addVisualModel(toolHandleModel); + + return scalpelHandle; +} + +std::shared_ptr<SceneObject> +makeBlade(std::string filename) +{ + imstkNew<SceneObject> scalpelBlade(filename); + auto blade10Mesh = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/Surgical Instruments/Scalpel/" + filename + ".obj"); + blade10Mesh->translate(0.0, 0.0, 1.0, Geometry::TransformType::ApplyToData); + blade10Mesh->rotate(Vec3d(0.0, 1.0, 0.0), 3.14, Geometry::TransformType::ApplyToData); + blade10Mesh->rotate(Vec3d(1.0, 0.0, 0.0), -1.57, Geometry::TransformType::ApplyToData); + blade10Mesh->scale(0.06, Geometry::TransformType::ApplyToData); + + imstkNew<VisualModel> blade10Model(blade10Mesh); + imstkNew<RenderMaterial> material; + material->setDisplayMode(RenderMaterial::DisplayMode::Surface); + material->setShadingModel(RenderMaterial::ShadingModel::PBR); + material->setMetalness(0.9f); + material->setRoughness(0.2f); + material->addTexture(std::make_shared<Texture>( + iMSTK_DATA_ROOT "/Surgical Instruments/Scalpel/Scalpel_Albedo.png", + Texture::Type::Diffuse)); + blade10Model->setRenderMaterial(material); + + scalpelBlade->addVisualModel(blade10Model); + return scalpelBlade; +} + +/// +/// \brief This example demonstrates rendering and controlling a SceneObject with OpenVR +/// as well as swapping a tool +/// +int +main() +{ + // Write log to stdout and file + Logger::startLogger(); + + // Setup the scene + imstkNew<Scene> scene("OpenVRControllerExample"); + + std::shared_ptr<SceneObject> scalpelHandle = makeHandleObject(); + scene->addSceneObject(scalpelHandle); + + std::shared_ptr<SceneObject> scalpelBlade10 = makeBlade("Scalpel_Blade10"); + scene->addSceneObject(scalpelBlade10); + + std::shared_ptr<SceneObject> scalpelBlade15 = makeBlade("Scalpel_Blade15"); + scene->addSceneObject(scalpelBlade15); + scalpelBlade15->getMasterGeometry()->setTranslation(0.2, 1.0, -0.8); + + // Lights + imstkNew<DirectionalLight> dirLight("DirLight"); + dirLight->setIntensity(4); + dirLight->setColor(Color(1.0, 0.95, 0.8)); + dirLight->setCastsShadow(true); + dirLight->setShadowRange(1.5); + scene->addLight(dirLight); + + { + // Add a module to run the viewer + imstkNew<VTKOpenVRViewer> viewer("VRViewer"); + viewer->setActiveScene(scene); + + // Add a module to run the scene + imstkNew<SceneManager> sceneManager("Scene Manager"); + sceneManager->setActiveScene(scene); + viewer->addChildThread(sceneManager); // Start/stop scene with the view + + // Add a VR controller for the scalpel handle + imstkNew<SceneObjectController> controller1(scalpelHandle, viewer->getVRDeviceClient(OPENVR_RIGHT_CONTROLLER)); + scene->addController(controller1); + // Add a VR controller for the scalpel blade + imstkNew<SceneObjectController> controller2(scalpelBlade10, viewer->getVRDeviceClient(OPENVR_RIGHT_CONTROLLER)); + scene->addController(controller2); + + // VRButtonPress emitted from viewer, recieve it in the scene that way the scene is not running whilst it is swapped + bool blade10InHand = true; + queueConnect<VRButtonEvent>(viewer->getVRDeviceClient(OPENVR_RIGHT_CONTROLLER), EventType::VRButtonPress, sceneManager, + [&](VRButtonEvent* e) + { + // When any button pressed, swap blade + // todo: distance metric not working + if (e->m_buttonState == BUTTON_PRESSED) + { + const Vec3d& posControl = viewer->getVRDeviceClient(OPENVR_RIGHT_CONTROLLER)->getPosition(); + if (blade10InHand) + { + // Swap to blade 15 only if it's close in space + Vec3d min, max; + scalpelBlade15->getMasterGeometry()->computeBoundingBox(min, max); + const Vec3d posBlade = (min + max) * 0.5; + const double dist = (posControl - posBlade).norm(); + LOG(INFO) << "Dist: " << dist; + if (dist < 2.0) + { + const Vec3d t = scalpelBlade15->getMasterGeometry()->getTranslation(); + const Mat3d r = scalpelBlade15->getMasterGeometry()->getRotation(); + + // Set the new blade to move + controller2->setControlledSceneObject(scalpelBlade15); + blade10InHand = false; + + scalpelBlade10->getMasterGeometry()->setTranslation(t); + scalpelBlade10->getMasterGeometry()->setRotation(r); + } + } + else + { + // Swap to blade 10 only if it's close in space + Vec3d min, max; + scalpelBlade10->getMasterGeometry()->computeBoundingBox(min, max); + const Vec3d posBlade = (min + max) * 0.5; + const double dist = (posControl - posBlade).norm(); + LOG(INFO) << "Dist: " << dist; + if (dist < 2.0) + { + const Vec3d t = scalpelBlade10->getMasterGeometry()->getTranslation(); + const Mat3d r = scalpelBlade10->getMasterGeometry()->getRotation(); + + controller2->setControlledSceneObject(scalpelBlade10); + blade10InHand = true; + + // Swap transforms of the blades + scalpelBlade15->getMasterGeometry()->setTranslation(t); + scalpelBlade15->getMasterGeometry()->setRotation(r); + } + } + } + }); + + // Start running + viewer->requestStatus(ThreadStatus::Running); + viewer->start(); + } + + return 0; +} \ No newline at end of file diff --git a/Examples/PBD/PBDCloth/pbdClothExample.cpp b/Examples/PBD/PBDCloth/pbdClothExample.cpp index 559dbe895d112603de365affedfcbf2546e54c2d..c1ef2d620fd52aa125d0258b2bcb89d77b22d196 100644 --- a/Examples/PBD/PBDCloth/pbdClothExample.cpp +++ b/Examples/PBD/PBDCloth/pbdClothExample.cpp @@ -19,14 +19,20 @@ =========================================================================*/ -#include "imstkSimulationManager.h" -#include "imstkPbdModel.h" -#include "imstkPbdObject.h" -#include "imstkAPIUtilities.h" -#include "imstkSurfaceMesh.h" #include "imstkCamera.h" +#include "imstkKeyboardSceneControl.h" #include "imstkLight.h" +#include "imstkLogger.h" +#include "imstkMouseSceneControl.h" +#include "imstkNew.h" +#include "imstkPbdModel.h" +#include "imstkPbdObject.h" +#include "imstkRenderMaterial.h" #include "imstkScene.h" +#include "imstkSceneManager.h" +#include "imstkSurfaceMesh.h" +#include "imstkVisualModel.h" +#include "imstkVTKViewer.h" using namespace imstk; @@ -39,14 +45,13 @@ const int nCols = 16; /// /// \brief Creates cloth geometry /// -static std::unique_ptr<SurfaceMesh> +static std::shared_ptr<SurfaceMesh> makeClothGeometry(const double width, const double height, const int nRows, const int nCols) { - // Create surface mesh - auto clothMesh = std::make_unique<SurfaceMesh>(); + imstkNew<SurfaceMesh> clothMesh; StdVectorOfVec3d vertList; vertList.resize(nRows * nCols); @@ -105,36 +110,36 @@ makeClothObj(const std::string& name, const int nRows, const int nCols) { - auto clothObj = std::make_shared<PbdObject>(name); + imstkNew<PbdObject> clothObj(name); // Setup the Geometry - std::shared_ptr<SurfaceMesh> clothMesh(std::move(makeClothGeometry(width, height, nRows, nCols))); + std::shared_ptr<SurfaceMesh> clothMesh(makeClothGeometry(width, height, nRows, nCols)); // Setup the Parameters - auto pbdParams = std::make_shared<PBDModelConfig>(); - pbdParams->enableConstraint(PbdConstraint::Type::Distance, 1e2); - pbdParams->enableConstraint(PbdConstraint::Type::Dihedral, 1e1); + imstkNew<PBDModelConfig> pbdParams; + pbdParams->enableConstraint(PbdConstraint::Type::Distance, 1.0e2); + pbdParams->enableConstraint(PbdConstraint::Type::Dihedral, 1.0e1); pbdParams->m_fixedNodeIds = { 0, static_cast<size_t>(nCols) - 1 }; pbdParams->m_uniformMassValue = width * height / ((double)nRows * (double)nCols); - pbdParams->m_gravity = Vec3d(0, -9.8, 0); + pbdParams->m_gravity = Vec3d(0.0, -9.8, 0.0); pbdParams->m_defaultDt = 0.005; pbdParams->m_iterations = 5; // Setup the Model - auto pbdModel = std::make_shared<PbdModel>(); + imstkNew<PbdModel> pbdModel; pbdModel->setModelGeometry(clothMesh); pbdModel->configure(pbdParams); // Setup the VisualModel - auto material = std::make_shared<RenderMaterial>(); + imstkNew<RenderMaterial> material; material->setBackFaceCulling(false); material->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface); - auto clothVisualModel = std::make_shared<VisualModel>(clothMesh); - clothVisualModel->setRenderMaterial(material); + imstkNew<VisualModel> visualModel(clothMesh); + visualModel->setRenderMaterial(material); // Setup the Object - clothObj->addVisualModel(clothVisualModel); + clothObj->addVisualModel(visualModel); clothObj->setPhysicsGeometry(clothMesh); clothObj->setDynamicalModel(pbdModel); @@ -148,34 +153,62 @@ makeClothObj(const std::string& name, int main() { - auto simManager = std::make_shared<SimulationManager>(); - auto scene = simManager->createNewScene("PBDCloth"); - - std::shared_ptr<PbdObject> clothObj = makeClothObj("Cloth", width, height, nRows, nCols); - scene->addSceneObject(clothObj); - - // Light (white) - auto whiteLight = std::make_shared<DirectionalLight>("whiteLight"); - whiteLight->setFocalPoint(Vec3d(5, -8, -5)); - whiteLight->setIntensity(1.); - scene->addLight(whiteLight); - - // Light (red) - auto colorLight = std::make_shared<SpotLight>("colorLight"); - colorLight->setPosition(Vec3d(-5., -3., 5.)); - colorLight->setFocalPoint(Vec3d(0., -5., 5.)); - colorLight->setIntensity(100.); - colorLight->setColor(Color::Red); - colorLight->setSpotAngle(30); - scene->addLight(colorLight); - - // Adjust camera - scene->getCamera()->setFocalPoint(0., -5., 5.); - scene->getCamera()->setPosition(-15., -5., 15.); - - // Start - simManager->setActiveScene(scene); - simManager->start(SimulationStatus::Paused); + // Write log to stdout and file + Logger::startLogger(); + + // Setup a scene + imstkNew<Scene> scene("PBDCloth"); + { + std::shared_ptr<PbdObject> clothObj = makeClothObj("Cloth", width, height, nRows, nCols); + scene->addSceneObject(clothObj); + + // Light (white) + imstkNew<DirectionalLight> whiteLight("whiteLight"); + whiteLight->setFocalPoint(Vec3d(5.0, -8.0, -5.0)); + whiteLight->setIntensity(1.0); + scene->addLight(whiteLight); + + // Light (red) + imstkNew<SpotLight> colorLight("colorLight"); + colorLight->setPosition(Vec3d(-5.0, -3.0, 5.0)); + colorLight->setFocalPoint(Vec3d(0.0, -5.0, 5.0)); + colorLight->setIntensity(100.); + colorLight->setColor(Color::Red); + colorLight->setSpotAngle(30.0); + scene->addLight(colorLight); + + // Adjust camera + scene->getActiveCamera()->setFocalPoint(0.0, -5.0, 5.0); + scene->getActiveCamera()->setPosition(-15.0, -5.0, 25.0); + } + + // Run the simulation + { + // Setup a viewer to render in its own thread + imstkNew<VTKViewer> viewer("Viewer"); + viewer->setActiveScene(scene); + + // Setup a scene manager to advance the scene in its own thread + imstkNew<SceneManager> sceneManager("Scene Manager"); + sceneManager->setActiveScene(scene); + viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer + + // Add mouse and keyboard controls to the viewer + { + imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice()); + mouseControl->setSceneManager(sceneManager); + viewer->addControl(mouseControl); + + imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice()); + keyControl->setSceneManager(sceneManager); + keyControl->setViewer(viewer); + viewer->addControl(keyControl); + } + + // Start viewer running, scene as paused + sceneManager->requestStatus(ThreadStatus::Paused); + viewer->start(); + } return 0; } diff --git a/Examples/PBD/PBDCollisionMultipleObjects/PBDCollisionMultipleObjectsExample.cpp b/Examples/PBD/PBDCollisionMultipleObjects/PBDCollisionMultipleObjectsExample.cpp index 1ef3a0b62544fbe0968405332810a253dd61fcc1..78983daaf645b24ee675d3fceb72f4d0c933a652 100644 --- a/Examples/PBD/PBDCollisionMultipleObjects/PBDCollisionMultipleObjectsExample.cpp +++ b/Examples/PBD/PBDCollisionMultipleObjects/PBDCollisionMultipleObjectsExample.cpp @@ -21,16 +21,23 @@ #include "imstkCamera.h" #include "imstkCollisionGraph.h" +#include "imstkKeyboardSceneControl.h" #include "imstkLight.h" +#include "imstkLogger.h" #include "imstkMeshIO.h" +#include "imstkMouseSceneControl.h" +#include "imstkNew.h" #include "imstkObjectInteractionFactory.h" #include "imstkOneToOneMap.h" #include "imstkPbdModel.h" #include "imstkPbdObject.h" +#include "imstkRenderMaterial.h" #include "imstkScene.h" -#include "imstkSimulationManager.h" +#include "imstkSceneManager.h" #include "imstkSurfaceMesh.h" #include "imstkTetrahedralMesh.h" +#include "imstkVisualModel.h" +#include "imstkVTKViewer.h" // Enable this macro to generate many dragons #define BIG_SCENE @@ -40,102 +47,12 @@ using namespace imstk; /// /// \brief Generate a random color /// -Color -getRandomColor() -{ - Color color(0, 0, 0, 1); - while (true) - { - for (unsigned int i = 0; i < 3; ++i) - { - color.rgba[i] = static_cast<double>(rand()) / static_cast<double>(RAND_MAX); - } - if (color.rgba[0] > 0.95 - || color.rgba[1] > 0.95 - || color.rgba[2] > 0.95) - { - break; - } - } - return color; -} - -void -generateDragon(const std::shared_ptr<imstk::Scene>& scene, - const Vec3d& translation, - std::shared_ptr<SurfaceMesh>& surfMesh, - std::shared_ptr<PbdObject>& deformableObj, - std::shared_ptr<PbdSolver>& pbdSolver) -{ - // Load a sample mesh - auto tetMesh = MeshIO::read(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg"); - LOG_IF(FATAL, (!tetMesh)) << "Could not read mesh from file."; - - auto volTetMesh = std::dynamic_pointer_cast<TetrahedralMesh>(tetMesh); - LOG_IF(FATAL, (!volTetMesh)) << "Dynamic pointer cast from PointSet to TetrahedralMesh failed!"; - - // Rotate a rando angle - volTetMesh->rotate(Vec3d(0, 1, 0), static_cast<double>(rand()), Geometry::TransformType::ApplyToData); - - // Translate - volTetMesh->translate(translation, Geometry::TransformType::ApplyToData); +Color getRandomColor(); - // Trick to force update geometry postUpdateTransform - const auto positions = volTetMesh->getVertexPositions(); - (void)positions; - - static int count = -1; - ++count; - surfMesh = std::make_shared<SurfaceMesh>("Dragon-" + std::to_string(count)); - volTetMesh->extractSurfaceMesh(surfMesh, true); - - auto material = std::make_shared<RenderMaterial>(); - -#if 0 - // Wireframe color - material->setDisplayMode(RenderMaterial::DisplayMode::WIREFRAME_SURFACE); - material->setColor(getRandomColor()); // Wireframe color - material->setLineWidth(2); -#else - material->setDisplayMode(RenderMaterial::DisplayMode::Surface); - material->setColor(getRandomColor()); -#endif - - auto surfMeshModel = std::make_shared<VisualModel>(surfMesh); - surfMeshModel->setRenderMaterial(material); - - auto deformMapP2C = std::make_shared<OneToOneMap>(tetMesh, surfMesh); - - deformableObj = std::make_shared<PbdObject>("Dragon-" + std::to_string(count)); - deformableObj->addVisualModel(surfMeshModel); - deformableObj->setCollidingGeometry(surfMesh); - deformableObj->setPhysicsGeometry(volTetMesh); - deformableObj->setPhysicsToCollidingMap(deformMapP2C); - - // Create model and object - auto pbdModel = std::make_shared<PbdModel>(); - pbdModel->setModelGeometry(volTetMesh); - - // configure model - auto pbdParams = std::make_shared<PBDModelConfig>(); - - // FEM constraint - pbdParams->m_femParams->m_YoungModulus = 1000.0; - pbdParams->m_femParams->m_PoissonRatio = 0.3; - pbdParams->enableFEMConstraint(PbdConstraint::Type::FEMTet, PbdFEMConstraint::MaterialType::StVK); - - // Other parameters - pbdParams->m_uniformMassValue = 5.0; - pbdParams->m_gravity = Vec3d(0, -1.0, 0); - pbdParams->m_defaultDt = 0.01; - pbdParams->m_iterations = 20; - pbdParams->collisionParams->m_proximity = 0.5; - - pbdModel->configure(pbdParams); - deformableObj->setDynamicalModel(pbdModel); - - scene->addSceneObject(deformableObj); -} +void generateDragon(const std::shared_ptr<imstk::Scene>& scene, + const Vec3d& translation, + std::shared_ptr<SurfaceMesh>& surfMesh, + std::shared_ptr<PbdObject>& deformableObj); /// /// \brief Create a surface mesh @@ -151,39 +68,35 @@ std::shared_ptr<SurfaceMesh> createUniformSurfaceMesh(const double width, const int main() { - auto simManager = std::make_shared<SimulationManager>(); - auto scene = simManager->createNewScene("PbdCollision"); + // Write log to stdout and file + Logger::startLogger(); - // Get the VTKViewer - std::shared_ptr<VTKViewer> viewer = std::make_shared<VTKViewer>(simManager.get(), false); - viewer->setWindowTitle("PbdCollision"); - viewer->getVtkRenderWindow()->SetSize(1920, 1080); - simManager->setViewer(viewer); + imstkNew<Scene> scene("PbdCollision"); - auto floorMesh = createUniformSurfaceMesh(100.0, 100.0, 2, 2); + std::shared_ptr<SurfaceMesh> floorMesh = createUniformSurfaceMesh(100.0, 100.0, 2, 2); - auto materialFloor = std::make_shared<RenderMaterial>(); - materialFloor->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface); - auto floorMeshModel = std::make_shared<VisualModel>(floorMesh); - floorMeshModel->setRenderMaterial(materialFloor); + imstkNew<RenderMaterial> floorMaterial; + floorMaterial->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface); + imstkNew<VisualModel> floorMeshModel(floorMesh); + floorMeshModel->setRenderMaterial(floorMaterial); - auto floorObj = std::make_shared<PbdObject>("Floor"); + imstkNew<PbdObject> floorObj("Floor"); floorObj->setCollidingGeometry(floorMesh); floorObj->setVisualGeometry(floorMesh); floorObj->setPhysicsGeometry(floorMesh); - auto pbdModel2 = std::make_shared<PbdModel>(); - pbdModel2->setModelGeometry(floorMesh); + imstkNew<PbdModel> pbdModel; + pbdModel->setModelGeometry(floorMesh); // configure model - auto pbdParams2 = std::make_shared<PBDModelConfig>(); - pbdParams2->m_uniformMassValue = 0.0; - pbdParams2->collisionParams->m_proximity = 0.1; - pbdParams2->m_iterations = 0; + imstkNew<PBDModelConfig> pbdParams; + pbdParams->m_uniformMassValue = 0.0; + pbdParams->collisionParams->m_proximity = 0.1; + pbdParams->m_iterations = 0; // Set the parameters - pbdModel2->configure(pbdParams2); - floorObj->setDynamicalModel(pbdModel2); + pbdModel->configure(pbdParams); + floorObj->setDynamicalModel(pbdModel); scene->addSceneObject(floorObj); #ifdef BIG_SCENE @@ -213,9 +126,8 @@ main() { std::shared_ptr<SurfaceMesh> mesh; std::shared_ptr<PbdObject> pbdObj; - std::shared_ptr<PbdSolver> solver; Vec3d translation(shiftX + i * distanceXZ, minHeight + j * distanceY, k * distanceXZ); - generateDragon(scene, translation, mesh, pbdObj, solver); + generateDragon(scene, translation, mesh, pbdObj); pbdObjs.push_back(pbdObj); scene->getCollisionGraph()->addInteraction(makeObjectInteractionPair(pbdObj, floorObj, @@ -234,30 +146,142 @@ main() } // Light - auto light = std::make_shared<DirectionalLight>("light"); + imstkNew<DirectionalLight> light("light"); light->setFocalPoint(Vec3d(5, -8, -5)); light->setIntensity(1); scene->addLight(light); // Set Camera configuration - auto cam = scene->getCamera(); + std::shared_ptr<Camera> cam = scene->getActiveCamera(); cam->setPosition(Vec3d(0, 15, 30)); cam->setFocalPoint(Vec3d(0, 0, 0)); - simManager->setActiveScene(scene); - simManager->start(SimulationStatus::Paused); + { + // Add a module to run the viewer + imstkNew<VTKViewer> viewer("Viewer"); + viewer->setActiveScene(scene); + viewer->setWindowTitle("PbdCollision"); + viewer->setSize(1920, 1080); + + // Add a module to run the scene + imstkNew<SceneManager> sceneManager("Scene Manager"); + sceneManager->setActiveScene(scene); + viewer->addChildThread(sceneManager); // Start/stop scene with the view + + // Add mouse and keyboard controls to the viewer + { + imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice()); + mouseControl->setSceneManager(sceneManager); + viewer->addControl(mouseControl); + + imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice()); + keyControl->setSceneManager(sceneManager); + keyControl->setViewer(viewer); + viewer->addControl(keyControl); + } + + // Start viewer running, scene as paused + sceneManager->requestStatus(ThreadStatus::Paused); + viewer->start(); + } return 0; } +Color +getRandomColor() +{ + Color color(0.0, 0.0, 0.0, 1.0); + while (true) + { + for (unsigned int i = 0; i < 3; ++i) + { + color.rgba[i] = static_cast<double>(rand()) / static_cast<double>(RAND_MAX); + } + if (color.rgba[0] > 0.95 + || color.rgba[1] > 0.95 + || color.rgba[2] > 0.95) + { + break; + } + } + return color; +} + +void +generateDragon(const std::shared_ptr<imstk::Scene>& scene, + const Vec3d& translation, + std::shared_ptr<SurfaceMesh>& surfMesh, + std::shared_ptr<PbdObject>& deformableObj) +{ + // Load a sample mesh + auto tetMesh = MeshIO::read<TetrahedralMesh>(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg"); + LOG_IF(FATAL, (!tetMesh)) << "Dynamic pointer cast from PointSet to TetrahedralMesh failed!"; + + // Rotate a rando angle + tetMesh->rotate(Vec3d(0, 1, 0), static_cast<double>(rand()), Geometry::TransformType::ApplyToData); + + // Translate + tetMesh->translate(translation, Geometry::TransformType::ApplyToData); + + // Trick to force update geometry postUpdateTransform + const auto positions = tetMesh->getVertexPositions(); + (void)positions; + + static int count = -1; + ++count; + surfMesh = std::make_shared<SurfaceMesh>("Dragon-" + std::to_string(count)); + tetMesh->extractSurfaceMesh(surfMesh, true); + + imstkNew<RenderMaterial> material; +#if 0 + // Wireframe color + material->setDisplayMode(RenderMaterial::DisplayMode::WIREFRAME_SURFACE); + material->setColor(getRandomColor()); // Wireframe color + material->setLineWidth(2); +#else + material->setDisplayMode(RenderMaterial::DisplayMode::Surface); + material->setColor(getRandomColor()); +#endif + + imstkNew<VisualModel> surfMeshModel(surfMesh); + surfMeshModel->setRenderMaterial(material); + + deformableObj = std::make_shared<PbdObject>("Dragon-" + std::to_string(count)); + deformableObj->addVisualModel(surfMeshModel); + deformableObj->setCollidingGeometry(surfMesh); + deformableObj->setPhysicsGeometry(tetMesh); + deformableObj->setPhysicsToCollidingMap(std::make_shared<OneToOneMap>(tetMesh, surfMesh)); + + // Create model and object + imstkNew<PbdModel> pbdModel; + pbdModel->setModelGeometry(tetMesh); + + // configure model + imstkNew<PBDModelConfig> pbdParams; + + // FEM constraint + pbdParams->m_femParams->m_YoungModulus = 1000.0; + pbdParams->m_femParams->m_PoissonRatio = 0.3; + pbdParams->enableFEMConstraint(PbdConstraint::Type::FEMTet, PbdFEMConstraint::MaterialType::StVK); + + // Other parameters + pbdParams->m_uniformMassValue = 5.0; + pbdParams->m_gravity = Vec3d(0, -1.0, 0); + pbdParams->m_defaultDt = 0.01; + pbdParams->m_iterations = 20; + pbdParams->collisionParams->m_proximity = 0.5; + + pbdModel->configure(pbdParams); + deformableObj->setDynamicalModel(pbdModel); + + scene->addSceneObject(deformableObj); +} + std::shared_ptr<SurfaceMesh> createUniformSurfaceMesh(const double width, const double height, const size_t nRows, const size_t nCols) { // Build floor geometry - // const double width = 100.0; - // const double height = 100.0; - // const size_t nRows = 2; - // const size_t nCols = 2; const double dy = width / static_cast<double>(nCols - 1); const double dx = height / static_cast<double>(nRows - 1); @@ -287,7 +311,7 @@ createUniformSurfaceMesh(const double width, const double height, const size_t n } } - auto surfMesh = std::make_shared<SurfaceMesh>(); + imstkNew<SurfaceMesh> surfMesh; surfMesh->initialize(vertList, triangles); return surfMesh; diff --git a/Examples/PBD/PBDCollisionOneObject/PBDCollisionOneObjectExample.cpp b/Examples/PBD/PBDCollisionOneObject/PBDCollisionOneObjectExample.cpp index 65a5343f8684602417e06675247e9ff405f11daa..8127569827271cb8d65be0c44159700962c8fa30 100644 --- a/Examples/PBD/PBDCollisionOneObject/PBDCollisionOneObjectExample.cpp +++ b/Examples/PBD/PBDCollisionOneObject/PBDCollisionOneObjectExample.cpp @@ -21,29 +21,30 @@ #include "imstkCamera.h" #include "imstkCollisionGraph.h" +#include "imstkKeyboardSceneControl.h" #include "imstkLight.h" +#include "imstkLogger.h" #include "imstkMeshIO.h" +#include "imstkMouseSceneControl.h" +#include "imstkNew.h" #include "imstkObjectInteractionFactory.h" #include "imstkOneToOneMap.h" #include "imstkPbdModel.h" #include "imstkPbdObject.h" +#include "imstkRenderMaterial.h" #include "imstkScene.h" -#include "imstkSimulationManager.h" +#include "imstkSceneManager.h" #include "imstkSurfaceMesh.h" -#include "imstkTaskGraphVizWriter.h" +#include "imstkTetrahedralMesh.h" #include "imstkTetraTriangleMap.h" +#include "imstkVisualModel.h" +#include "imstkVTKViewer.h" using namespace imstk; // mesh file names const std::string surfMeshFileName = iMSTK_DATA_ROOT "/asianDragon/asianDragon.obj"; const std::string tetMeshFileName = iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg"; -/// -/// \brief Create a surface mesh -/// \param nRows number of vertices in x-direction -/// \param nCols number of vertices in y-direction -/// -std::shared_ptr<SurfaceMesh> createUniformSurfaceMesh(const double width, const double height, const size_t nRows, const size_t nCols); // parameters to play with const double youngModulus = 1000.0; @@ -52,6 +53,13 @@ const double timeStep = 0.01; const double contactStiffness = 0.1; const int maxIter = 5; +/// +/// \brief Create a surface mesh +/// \param nRows number of vertices in x-direction +/// \param nCols number of vertices in y-direction +/// +std::shared_ptr<SurfaceMesh> createUniformSurfaceMesh(const double width, const double height, const size_t nRows, const size_t nCols); + /// /// \brief This example demonstrates the collision interaction /// using Position based dynamics @@ -59,106 +67,131 @@ const int maxIter = 5; int main() { - auto simManager = std::make_shared<SimulationManager>(); - auto scene = simManager->createNewScene("PbdCollisionOneDragon"); - scene->getCamera()->setPosition(0, 3.0, 20.0); - scene->getCamera()->setFocalPoint(0.0, -10.0, 0.0); - - // set up the meshes - auto highResSurfMesh = std::dynamic_pointer_cast<SurfaceMesh>(MeshIO::read(surfMeshFileName)); - auto coarseTetMesh = std::dynamic_pointer_cast<TetrahedralMesh>(MeshIO::read(tetMeshFileName)); - auto coarseSurfMesh = std::make_shared<SurfaceMesh>(); - coarseTetMesh->extractSurfaceMesh(coarseSurfMesh, true); - - // set up maps - auto mapPhysicsToVisual = std::make_shared<TetraTriangleMap>(coarseTetMesh, highResSurfMesh); - auto mapCollisionToPhysics = std::make_shared<OneToOneMap>(coarseTetMesh, coarseSurfMesh); - - // set up visual model based on high res mesh - auto material = std::make_shared<RenderMaterial>(); - material->setDisplayMode(RenderMaterial::DisplayMode::Surface); - material->setLineWidth(0.5); - material->setEdgeColor(Color::Blue); - material->setShadingModel(RenderMaterial::ShadingModel::Phong); - auto surfMeshModel = std::make_shared<VisualModel>(highResSurfMesh); - surfMeshModel->setRenderMaterial(material); - - // configure the deformable object - auto deformableObj = std::make_shared<PbdObject>("DeformableObj"); - deformableObj->addVisualModel(surfMeshModel); - deformableObj->setCollidingGeometry(coarseSurfMesh); - deformableObj->setPhysicsGeometry(coarseTetMesh); - deformableObj->setPhysicsToCollidingMap(mapCollisionToPhysics); - deformableObj->setPhysicsToVisualMap(mapPhysicsToVisual); - - // Create model and object - auto pbdModel = std::make_shared<PbdModel>(); - pbdModel->setModelGeometry(coarseTetMesh); - - // configure model - auto pbdParams = std::make_shared<PBDModelConfig>(); - - // FEM constraint - pbdParams->m_femParams->m_YoungModulus = youngModulus; - pbdParams->m_femParams->m_PoissonRatio = poissonRatio; - pbdParams->enableFEMConstraint(PbdConstraint::Type::FEMTet, - PbdFEMConstraint::MaterialType::Corotation); - - // Other parameters - // \todo use lumped mass - pbdParams->m_uniformMassValue = 1.0; - - pbdParams->m_gravity = Vec3d(0, -10.0, 0); - pbdParams->m_defaultDt = timeStep; - pbdParams->m_iterations = maxIter; - pbdParams->collisionParams->m_proximity = 0.3; - pbdParams->collisionParams->m_stiffness = 0.1; - - pbdModel->configure(pbdParams); - deformableObj->setDynamicalModel(pbdModel); - - scene->addSceneObject(deformableObj); - - // Build floor geometry - auto floorMesh = createUniformSurfaceMesh(100.0, 100.0, 2, 2); - - auto materialFloor = std::make_shared<RenderMaterial>(); - materialFloor->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface); - auto floorMeshModel = std::make_shared<VisualModel>(floorMesh); - floorMeshModel->setRenderMaterial(materialFloor); - - auto floor = std::make_shared<PbdObject>("Floor"); - floor->setCollidingGeometry(floorMesh); - floor->setVisualGeometry(floorMesh); - floor->setPhysicsGeometry(floorMesh); - - auto pbdModel2 = std::make_shared<PbdModel>(); - pbdModel2->setModelGeometry(floorMesh); - - // configure model - auto pbdParams2 = std::make_shared<PBDModelConfig>(); - pbdParams2->m_uniformMassValue = 0.0; - pbdParams2->m_iterations = 0; - pbdParams2->collisionParams->m_proximity = -0.1; - - // Set the parameters - pbdModel2->configure(pbdParams2); - floor->setDynamicalModel(pbdModel2); - - scene->addSceneObject(floor); - - // Collision - scene->getCollisionGraph()->addInteraction(makeObjectInteractionPair(deformableObj, floor, - InteractionType::PbdObjToPbdObjCollision, CollisionDetection::Type::MeshToMeshBruteForce)); - - // Light - auto light = std::make_shared<DirectionalLight>("light"); - light->setFocalPoint(Vec3d(5, -8, -5)); - light->setIntensity(1); - scene->addLight(light); - - simManager->setActiveScene(scene); - simManager->start(SimulationStatus::Paused); + // Setup logger (write to file and stdout) + Logger::startLogger(); + + // Setup the scene + imstkNew<Scene> scene("PbdCollisionOneDragon"); + { + scene->getActiveCamera()->setPosition(0, 3.0, 20.0); + scene->getActiveCamera()->setFocalPoint(0.0, -10.0, 0.0); + + // set up the meshes + auto highResSurfMesh = MeshIO::read<SurfaceMesh>(surfMeshFileName); + auto coarseTetMesh = MeshIO::read<TetrahedralMesh>(tetMeshFileName); + imstkNew<SurfaceMesh> coarseSurfMesh; + coarseTetMesh->extractSurfaceMesh(coarseSurfMesh, true); + + // set up visual model based on high res mesh + imstkNew<RenderMaterial> material; + material->setDisplayMode(RenderMaterial::DisplayMode::Surface); + material->setLineWidth(0.5); + material->setEdgeColor(Color::Blue); + material->setShadingModel(RenderMaterial::ShadingModel::Phong); + imstkNew<VisualModel> surfMeshModel(highResSurfMesh); + surfMeshModel->setRenderMaterial(material); + + // configure the deformable object + imstkNew<PbdObject> deformableObj("DeformableObj"); + deformableObj->addVisualModel(surfMeshModel); + deformableObj->setCollidingGeometry(coarseSurfMesh); + deformableObj->setPhysicsGeometry(coarseTetMesh); + deformableObj->setPhysicsToCollidingMap(std::make_shared<OneToOneMap>(coarseTetMesh, coarseSurfMesh)); + deformableObj->setPhysicsToVisualMap(std::make_shared<TetraTriangleMap>(coarseTetMesh, highResSurfMesh)); + + // Create model and object + imstkNew<PbdModel> pbdModel; + pbdModel->setModelGeometry(coarseTetMesh); + + // configure model + imstkNew<PBDModelConfig> pbdParams; + + // FEM constraint + pbdParams->m_femParams->m_YoungModulus = youngModulus; + pbdParams->m_femParams->m_PoissonRatio = poissonRatio; + pbdParams->enableFEMConstraint(PbdConstraint::Type::FEMTet, + PbdFEMConstraint::MaterialType::Corotation); + + // Other parameters + // \todo use lumped mass + pbdParams->m_uniformMassValue = 1.0; + pbdParams->m_gravity = Vec3d(0, -10.0, 0); + pbdParams->m_defaultDt = timeStep; + pbdParams->m_iterations = maxIter; + pbdParams->collisionParams->m_proximity = 0.3; + pbdParams->collisionParams->m_stiffness = 0.1; + + pbdModel->configure(pbdParams); + deformableObj->setDynamicalModel(pbdModel); + + scene->addSceneObject(deformableObj); + + // Build floor geometry + auto floorMesh = createUniformSurfaceMesh(100.0, 100.0, 2, 2); + + imstkNew<RenderMaterial> floorMaterial; + floorMaterial->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface); + imstkNew<VisualModel> floorVisualModel(floorMesh); + floorVisualModel->setRenderMaterial(floorMaterial); + + imstkNew<PbdObject> floorObj("Floor"); + floorObj->setCollidingGeometry(floorMesh); + floorObj->setPhysicsGeometry(floorMesh); + floorObj->addVisualModel(floorVisualModel); + + imstkNew<PbdModel> floorPbdModel; + floorPbdModel->setModelGeometry(floorMesh); + + // configure model + imstkNew<PBDModelConfig> floorPbdParams; + floorPbdParams->m_uniformMassValue = 0.0; + floorPbdParams->m_iterations = 0; + floorPbdParams->collisionParams->m_proximity = -0.1; + + // Set the parameters + floorPbdModel->configure(floorPbdParams); + floorObj->setDynamicalModel(floorPbdModel); + + scene->addSceneObject(floorObj); + + // Collision + scene->getCollisionGraph()->addInteraction(makeObjectInteractionPair(deformableObj, floorObj, + InteractionType::PbdObjToPbdObjCollision, CollisionDetection::Type::MeshToMeshBruteForce)); + + // Light + imstkNew<DirectionalLight> light("Light"); + light->setFocalPoint(Vec3d(5, -8, -5)); + light->setIntensity(1); + scene->addLight(light); + } + + // Run the simulation + { + // Setup a viewer to render in its own thread + imstkNew<VTKViewer> viewer("Viewer"); + viewer->setActiveScene(scene); + + // Setup a scene manager to advance the scene in its own thread + imstkNew<SceneManager> sceneManager("Scene Manager"); + sceneManager->setActiveScene(scene); + viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer + + // Add mouse and keyboard controls to the viewer + { + imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice()); + mouseControl->setSceneManager(sceneManager); + viewer->addControl(mouseControl); + + imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice()); + keyControl->setSceneManager(sceneManager); + keyControl->setViewer(viewer); + viewer->addControl(keyControl); + } + + // Start viewer running, scene as paused + sceneManager->requestStatus(ThreadStatus::Paused); + viewer->start(); + } return 0; } @@ -196,7 +229,7 @@ createUniformSurfaceMesh(const double width, const double height, const size_t n } } - auto surfMesh = std::make_shared<SurfaceMesh>(); + imstkNew<SurfaceMesh> surfMesh; surfMesh->initialize(vertList, triangles); return surfMesh; } diff --git a/Examples/PBD/PBDCollisionStairs/PBDCollisionStairsExample.cpp b/Examples/PBD/PBDCollisionStairs/PBDCollisionStairsExample.cpp index 823992faad968ce755ba22ec7130c1cc3dc7b9e2..e513ebc6ce2fb7a257732394782166983b8a0723 100644 --- a/Examples/PBD/PBDCollisionStairs/PBDCollisionStairsExample.cpp +++ b/Examples/PBD/PBDCollisionStairs/PBDCollisionStairsExample.cpp @@ -21,27 +21,30 @@ #include "imstkCamera.h" #include "imstkCollisionGraph.h" +#include "imstkKeyboardSceneControl.h" #include "imstkLight.h" +#include "imstkLogger.h" #include "imstkMeshIO.h" -#include "imstkMeshToMeshBruteForceCD.h" -#include "imstkOneToOneMap.h" -#include "imstkPBDCollisionHandling.h" +#include "imstkMouseSceneControl.h" +#include "imstkNew.h" +#include "imstkObjectInteractionFactory.h" #include "imstkPbdModel.h" #include "imstkPbdObject.h" -#include "imstkPbdSolver.h" +#include "imstkRenderMaterial.h" #include "imstkScene.h" -#include "imstkSimulationManager.h" +#include "imstkSceneManager.h" #include "imstkSurfaceMesh.h" #include "imstkTetrahedralMesh.h" #include "imstkTetraTriangleMap.h" -#include "imstkObjectInteractionFactory.h" +#include "imstkVisualModel.h" +#include "imstkVTKViewer.h" using namespace imstk; /// /// \brief Creates a non-manifold top part of a staircase // -static std::unique_ptr<SurfaceMesh> +static std::shared_ptr<SurfaceMesh> buildStairs(int nSteps, double width, double height, double depth) { // Build stair geometry @@ -90,7 +93,7 @@ buildStairs(int nSteps, double width, double height, double depth) triangles.push_back({ { (i + 1) * 4, (i + 1) * 4 + 1, i * 4 + 3 } }); } - std::unique_ptr<SurfaceMesh> stairMesh = std::make_unique<SurfaceMesh>(); + imstkNew<SurfaceMesh> stairMesh; stairMesh->initialize(vertList, triangles); return stairMesh; } @@ -101,18 +104,18 @@ buildStairs(int nSteps, double width, double height, double depth) static std::shared_ptr<PbdObject> makeArmadilloPbdObject(const std::string& name) { - auto pbdObj = std::make_shared<PbdObject>(name); + imstkNew<PbdObject> pbdObj(name); // Read in the armadillo mesh - auto tetMesh = std::dynamic_pointer_cast<TetrahedralMesh>(MeshIO::read(iMSTK_DATA_ROOT "armadillo/armadillo_volume.vtk")); + auto tetMesh = MeshIO::read<TetrahedralMesh>(iMSTK_DATA_ROOT "armadillo/armadillo_volume.vtk"); tetMesh->scale(0.07, Geometry::TransformType::ApplyToData); tetMesh->rotate(Vec3d(1.0, 0.0, 0.0), 1.3, Geometry::TransformType::ApplyToData); tetMesh->translate(Vec3d(0.0f, 10.0f, 0.0f), Geometry::TransformType::ApplyToData); - auto surfMesh = std::make_shared<SurfaceMesh>(); + imstkNew<SurfaceMesh> surfMesh; tetMesh->extractSurfaceMesh(surfMesh, true); // Setup the Parameters - auto pbdParams = std::make_shared<PBDModelConfig>(); + imstkNew<PBDModelConfig> pbdParams; pbdParams->m_femParams->m_YoungModulus = 1000.0; pbdParams->m_femParams->m_PoissonRatio = 0.3; pbdParams->enableFEMConstraint(PbdConstraint::Type::FEMTet, @@ -125,14 +128,14 @@ makeArmadilloPbdObject(const std::string& name) pbdParams->collisionParams->m_stiffness = 0.1; // Setup the Model - auto pbdModel = std::make_shared<PbdModel>(); + imstkNew<PbdModel> pbdModel; pbdModel->setModelGeometry(tetMesh); pbdModel->configure(pbdParams); // Setup the VisualModel - auto material = std::make_shared<RenderMaterial>(); + imstkNew<RenderMaterial> material; material->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface); - auto surfMeshModel = std::make_shared<VisualModel>(surfMesh); + imstkNew<VisualModel> surfMeshModel(surfMesh.get()); surfMeshModel->setRenderMaterial(material); // Setup the Object @@ -148,31 +151,30 @@ makeArmadilloPbdObject(const std::string& name) static std::shared_ptr<PbdObject> makeStairsPbdObject(const std::string& name, int numSteps, double width, double height, double depth) { - auto stairObj = std::make_shared<PbdObject>(name); + imstkNew<PbdObject> stairObj(name); - std::shared_ptr<SurfaceMesh> stairMesh(std::move(buildStairs(numSteps, width, height, depth))); + std::shared_ptr<SurfaceMesh> stairMesh = buildStairs(numSteps, width, height, depth); // Setup the parameters - auto pbdParams = std::make_shared<PBDModelConfig>(); + imstkNew<PBDModelConfig> pbdParams; pbdParams->m_uniformMassValue = 0.0; pbdParams->collisionParams->m_proximity = -0.1; pbdParams->m_iterations = 0; // Setup the model - auto pbdModel = std::make_shared<PbdModel>(); + imstkNew<PbdModel> pbdModel; pbdModel->setModelGeometry(stairMesh); pbdModel->configure(pbdParams); // Setup the VisualModel - auto stairMaterial = std::make_shared<RenderMaterial>(); + imstkNew<RenderMaterial> stairMaterial; stairMaterial->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface); - auto stairMeshModel = std::make_shared<VisualModel>(stairMesh); - stairMeshModel->setRenderMaterial(stairMaterial); + imstkNew<VisualModel> visualModel(stairMesh); + visualModel->setRenderMaterial(stairMaterial); - stairObj->addVisualModel(stairMeshModel); + stairObj->addVisualModel(visualModel); stairObj->setDynamicalModel(pbdModel); stairObj->setCollidingGeometry(stairMesh); - stairObj->setVisualGeometry(stairMesh); stairObj->setPhysicsGeometry(stairMesh); return stairObj; @@ -185,35 +187,64 @@ makeStairsPbdObject(const std::string& name, int numSteps, double width, double int main() { - auto simManager = std::make_shared<SimulationManager>(); - auto scene = simManager->createNewScene("PbdStairsCollision"); - scene->getCamera()->setPosition(0.0, 0.0, -30.0); - scene->getCamera()->setFocalPoint(0.0, 0.0, 0.0); - - // Create and add the dragon to the scene - auto pbdDragon1 = makeArmadilloPbdObject("PbdArmadillo1"); - scene->addSceneObject(pbdDragon1); - - auto stairObj = makeStairsPbdObject("PbdStairs", 12, 20.0, 10.0, 20.0); - scene->addSceneObject(stairObj); - - // Collision - scene->getCollisionGraph()->addInteraction(makeObjectInteractionPair(pbdDragon1, stairObj, - InteractionType::PbdObjToPbdObjCollision, CollisionDetection::Type::MeshToMeshBruteForce)); - - // Light - auto light = std::make_shared<DirectionalLight>("Light"); - light->setFocalPoint(Vec3d(5.0, -8.0, 5.0)); - light->setIntensity(1.0); - scene->addLight(light); - - auto light2 = std::make_shared<DirectionalLight>("light 2"); - light2->setFocalPoint(-Vec3d(5, -8, 5)); - light2->setIntensity(1.2); - scene->addLight(light2); - - simManager->setActiveScene(scene); - simManager->start(SimulationStatus::Paused); + // Setup logger (write to file and stdout) + Logger::startLogger(); + + imstkNew<Scene> scene("PbdStairsCollision"); + { + scene->getActiveCamera()->setPosition(0.0, 0.0, -30.0); + scene->getActiveCamera()->setFocalPoint(0.0, 0.0, 0.0); + + // Create and add the dragon to the scene + auto pbdDragon1 = makeArmadilloPbdObject("Armadillo"); + scene->addSceneObject(pbdDragon1); + + auto stairObj = makeStairsPbdObject("PbdStairs", 12, 20.0, 10.0, 20.0); + scene->addSceneObject(stairObj); + + // Collision + scene->getCollisionGraph()->addInteraction(makeObjectInteractionPair(pbdDragon1, stairObj, + InteractionType::PbdObjToPbdObjCollision, CollisionDetection::Type::MeshToMeshBruteForce)); + + // Light + imstkNew<DirectionalLight> light("Light1"); + light->setFocalPoint(Vec3d(5.0, -8.0, 5.0)); + light->setIntensity(1.0); + scene->addLight(light); + + imstkNew<DirectionalLight> light2("Light2"); + light2->setFocalPoint(-Vec3d(5, -8, 5)); + light2->setIntensity(1.2); + scene->addLight(light2); + } + + // Run the simulation + { + // Setup a viewer to render in its own thread + imstkNew<VTKViewer> viewer("Viewer"); + viewer->setActiveScene(scene); + + // Setup a scene manager to advance the scene in its own thread + imstkNew<SceneManager> sceneManager("Scene Manager"); + sceneManager->setActiveScene(scene); + viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer + + // Add mouse and keyboard controls to the viewer + { + imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice()); + mouseControl->setSceneManager(sceneManager); + viewer->addControl(mouseControl); + + imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice()); + keyControl->setSceneManager(sceneManager); + keyControl->setViewer(viewer); + viewer->addControl(keyControl); + } + + // Start viewer running, scene as paused + sceneManager->requestStatus(ThreadStatus::Paused); + viewer->start(); + } return 0; } diff --git a/Examples/PBD/PBDDeformableObject/PBD3DDeformableObject.cpp b/Examples/PBD/PBDDeformableObject/PBD3DDeformableObject.cpp index f309e978d20afc58bda4f09c26d13a7736df1a6a..a5ce8f84e09a5edf60dca48f3a7b2f2ccae57bdd 100644 --- a/Examples/PBD/PBDDeformableObject/PBD3DDeformableObject.cpp +++ b/Examples/PBD/PBDDeformableObject/PBD3DDeformableObject.cpp @@ -19,29 +19,30 @@ =========================================================================*/ -#include "imstkSimulationManager.h" +#include "imstkCamera.h" +#include "imstkKeyboardSceneControl.h" #include "imstkLight.h" +#include "imstkLogger.h" #include "imstkMeshIO.h" +#include "imstkMouseSceneControl.h" +#include "imstkNew.h" #include "imstkPbdModel.h" #include "imstkPbdObject.h" -#include "imstkOneToOneMap.h" -#include "imstkAPIUtilities.h" -#include "imstkTetraTriangleMap.h" -#include "imstkSurfaceMesh.h" -#include "imstkCamera.h" -#include "imstkPlane.h" +#include "imstkRenderMaterial.h" #include "imstkScene.h" - -#include <array> -#include <string> +#include "imstkSceneManager.h" +#include "imstkSurfaceMesh.h" +#include "imstkTetrahedralMesh.h" +#include "imstkTetraTriangleMap.h" +#include "imstkVisualModel.h" +#include "imstkVTKViewer.h" using namespace imstk; /// /// \brief Create a PbdObject and add it to a \p scene /// -std::shared_ptr<PbdObject> createAndAddPbdObject(std::shared_ptr<Scene> scene, - const std::string& tetMeshName); +std::shared_ptr<PbdObject> createAndAddPbdObject(const std::string& tetMeshName); // mesh file names const std::string& tetMeshFileName = iMSTK_DATA_ROOT "textured_organs/heart_volume.vtk"; @@ -53,38 +54,62 @@ const std::string& tetMeshFileName = iMSTK_DATA_ROOT "textured_organs/heart_volu int main() { - auto simManager = std::make_shared<SimulationManager>(); - auto scene = simManager->createNewScene("PBDVolume"); - scene->getCamera()->setPosition(0, 2.0, 15.0); + // Setup logger (write to file and stdout) + Logger::startLogger(); + + imstkNew<Scene> scene("PBDVolume"); + scene->getActiveCamera()->setPosition(0, 2.0, 15.0); // create and add a PBD object - createAndAddPbdObject(scene, tetMeshFileName); + scene->addSceneObject(createAndAddPbdObject(tetMeshFileName)); // Light - auto light = std::make_shared<DirectionalLight>("light"); + imstkNew<DirectionalLight> light("light"); light->setFocalPoint(Vec3d(5, -8, -5)); light->setIntensity(1.1); scene->addLight(light); - simManager->setActiveScene(scene); - simManager->getViewer()->setBackgroundColors(Vec3d(0.3285, 0.3285, 0.6525), Vec3d(0.13836, 0.13836, 0.2748), true); - simManager->start(SimulationStatus::Paused); + // Run the simulation + { + // Setup a viewer to render in its own thread + imstkNew<VTKViewer> viewer("Viewer"); + viewer->setActiveScene(scene); + viewer->setBackgroundColors(Vec3d(0.3285, 0.3285, 0.6525), Vec3d(0.13836, 0.13836, 0.2748), true); + + // Setup a scene manager to advance the scene in its own thread + imstkNew<SceneManager> sceneManager("Scene Manager"); + sceneManager->setActiveScene(scene); + viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer + + // Add mouse and keyboard controls to the viewer + { + imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice()); + mouseControl->setSceneManager(sceneManager); + viewer->addControl(mouseControl); + + imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice()); + keyControl->setSceneManager(sceneManager); + keyControl->setViewer(viewer); + viewer->addControl(keyControl); + } + + // Start viewer running, scene as paused + sceneManager->requestStatus(ThreadStatus::Paused); + viewer->start(); + } return 0; } std::shared_ptr<PbdObject> -createAndAddPbdObject(std::shared_ptr<Scene> scene, - const std::string& tetMeshName) +createAndAddPbdObject(const std::string& tetMeshName) { - auto tetMesh = std::dynamic_pointer_cast<TetrahedralMesh>(MeshIO::read(tetMeshName)); + auto tetMesh = MeshIO::read<TetrahedralMesh>(tetMeshName); tetMesh->rotate(Vec3d(1.0, 0.0, 0.0), -1.3, Geometry::TransformType::ApplyToData); - auto surfMesh = std::make_shared<SurfaceMesh>(); + imstkNew<SurfaceMesh> surfMesh; tetMesh->extractSurfaceMesh(surfMesh, true); - auto map = std::make_shared<TetraTriangleMap>(tetMesh, surfMesh); - - auto material = std::make_shared<RenderMaterial>(); + imstkNew<RenderMaterial> material; material->setDisplayMode(RenderMaterial::DisplayMode::Surface); material->setColor(Color(220. / 255.0, 100. / 255.0, 70. / 255.0)); material->setMetalness(100.9f); @@ -93,15 +118,15 @@ createAndAddPbdObject(std::shared_ptr<Scene> scene, material->setAmbientLightCoeff(50.); material->setShadingModel(RenderMaterial::ShadingModel::Phong); material->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface); - auto surfMeshModel = std::make_shared<VisualModel>(surfMesh); - surfMeshModel->setRenderMaterial(material); + imstkNew<VisualModel> visualModel(surfMesh.get()); + visualModel->setRenderMaterial(material); - auto deformableObj = std::make_shared<PbdObject>("DeformableObject"); - auto pbdModel = std::make_shared<PbdModel>(); + imstkNew<PbdObject> deformableObj("DeformableObject"); + imstkNew<PbdModel> pbdModel; pbdModel->setModelGeometry(tetMesh); - // configure model - auto pbdParams = std::make_shared<PBDModelConfig>(); + // Configure model + imstkNew<PBDModelConfig> pbdParams; // FEM constraint pbdParams->m_femParams->m_YoungModulus = 500.0; @@ -120,11 +145,9 @@ createAndAddPbdObject(std::shared_ptr<Scene> scene, pbdModel->setTimeStepSizeType(imstk::TimeSteppingType::Fixed); deformableObj->setDynamicalModel(pbdModel); - deformableObj->addVisualModel(surfMeshModel); + deformableObj->addVisualModel(visualModel); deformableObj->setPhysicsGeometry(tetMesh); - deformableObj->setPhysicsToVisualMap(map); //assign the computed map - - scene->addSceneObject(deformableObj); + deformableObj->setPhysicsToVisualMap(std::make_shared<TetraTriangleMap>(tetMesh, surfMesh)); return deformableObj; } diff --git a/Examples/PBD/PBDFluids/CMakeLists.txt b/Examples/PBD/PBDFluids/CMakeLists.txt index af7b92b1d3e7c4248dfa9af5a01c42488bb823db..7a7f4b6925c227fdd45bc1a0ceeebcdc6a6b460a 100644 --- a/Examples/PBD/PBDFluids/CMakeLists.txt +++ b/Examples/PBD/PBDFluids/CMakeLists.txt @@ -35,4 +35,4 @@ SET_TARGET_PROPERTIES (${PROJECT_NAME} PROPERTIES FOLDER Examples/PBD) #----------------------------------------------------------------------------- # Link libraries to executable #----------------------------------------------------------------------------- -target_link_libraries(${PROJECT_NAME} SimulationManager apiUtilities) +target_link_libraries(${PROJECT_NAME} SimulationManager) diff --git a/Examples/PBD/PBDFluids/PBDFluidsExample.cpp b/Examples/PBD/PBDFluids/PBDFluidsExample.cpp index eb4639c3735215d94fecbaaba031851a7d1adb4d..79a40cbaca0650f4548a932ecb46f29b53b5a240 100644 --- a/Examples/PBD/PBDFluids/PBDFluidsExample.cpp +++ b/Examples/PBD/PBDFluids/PBDFluidsExample.cpp @@ -19,19 +19,23 @@ =========================================================================*/ -#include "imstkAPIUtilities.h" #include "imstkCamera.h" #include "imstkCollisionGraph.h" +#include "imstkKeyboardSceneControl.h" #include "imstkLight.h" +#include "imstkLogger.h" #include "imstkMeshIO.h" -#include "imstkMeshToMeshBruteForceCD.h" +#include "imstkMouseSceneControl.h" +#include "imstkNew.h" #include "imstkObjectInteractionFactory.h" -#include "imstkPBDCollisionHandling.h" #include "imstkPbdModel.h" #include "imstkPbdObject.h" +#include "imstkRenderMaterial.h" #include "imstkScene.h" -#include "imstkSimulationManager.h" +#include "imstkSceneManager.h" #include "imstkSurfaceMesh.h" +#include "imstkVisualModel.h" +#include "imstkVTKViewer.h" using namespace imstk; @@ -56,53 +60,73 @@ const std::string tetMeshFileName = iMSTK_DATA_ROOT "/asianDragon/asianDragon.ve int main() { - auto simManager = std::make_shared<SimulationManager>(); - auto scene = simManager->createNewScene("PBDFluid"); + // Setup logger (write to file and stdout) + Logger::startLogger(); - scene->getCamera()->setPosition(0, 10.0, 15.0); + imstkNew<Scene> scene("PBDFluid"); + { + scene->getActiveCamera()->setPosition(0.0, 15.0, 20.0); - auto deformableObj = createAndAddPbdObject(scene, tetMeshFileName); - auto floorMeshColliding = createCollidingSurfaceMesh(); - auto floorMeshVisual = std::make_shared<SurfaceMesh>(); - floorMeshVisual->initialize(floorMeshColliding->getVertexPositions(), floorMeshColliding->getTrianglesVertices()); - auto floorMeshPhysics = std::make_shared<SurfaceMesh>(); - floorMeshPhysics->initialize(floorMeshColliding->getVertexPositions(), floorMeshColliding->getTrianglesVertices()); + std::shared_ptr<PbdObject> deformableObj = createAndAddPbdObject(scene, tetMeshFileName); + std::shared_ptr<SurfaceMesh> floorMeshColliding = createCollidingSurfaceMesh(); - auto floor = std::make_shared<PbdObject>("Floor"); - floor->setCollidingGeometry(floorMeshColliding); - floor->setVisualGeometry(floorMeshVisual); - floor->setPhysicsGeometry(floorMeshPhysics); + imstkNew<PbdObject> floorObj("Floor"); + floorObj->setCollidingGeometry(floorMeshColliding); + floorObj->setVisualGeometry(floorMeshColliding); + floorObj->setPhysicsGeometry(floorMeshColliding); - auto pbdModel2 = std::make_shared<PbdModel>(); - pbdModel2->setModelGeometry(floorMeshPhysics); + imstkNew<PbdModel> pbdModel; + pbdModel->setModelGeometry(floorMeshColliding); - // Configure model - auto pbdParams2 = std::make_shared<PBDModelConfig>(); - pbdParams2->m_uniformMassValue = 0.0; - pbdParams2->collisionParams->m_proximity = 0.1; + // Configure model + imstkNew<PBDModelConfig> pbdParams; + pbdParams->m_uniformMassValue = 0.0; + pbdParams->collisionParams->m_proximity = 0.1; - pbdModel2->configure(pbdParams2); - floor->setDynamicalModel(pbdModel2); + pbdModel->configure(pbdParams); + floorObj->setDynamicalModel(pbdModel); - scene->addSceneObject(floor); + scene->addSceneObject(floorObj); - // Collisions - scene->getCollisionGraph()->addInteraction(makeObjectInteractionPair(deformableObj, floor, - InteractionType::PbdObjToPbdObjCollision, - CollisionDetection::Type::MeshToMeshBruteForce)); + // Collisions + scene->getCollisionGraph()->addInteraction(makeObjectInteractionPair(deformableObj, floorObj, + InteractionType::PbdObjToPbdObjCollision, + CollisionDetection::Type::MeshToMeshBruteForce)); - // Light (white) - auto whiteLight = std::make_shared<DirectionalLight>("whiteLight"); - whiteLight->setFocalPoint(Vec3d(5, -8, -5)); - whiteLight->setIntensity(7); - scene->addLight(whiteLight); + // Light (white) + imstkNew<DirectionalLight> whiteLight("whiteLight"); + whiteLight->setFocalPoint(Vec3d(5.0, -8.0, -5.0)); + whiteLight->setIntensity(7); + scene->addLight(whiteLight); + } + + // Run the simulation + { + // Setup a viewer to render in its own thread + imstkNew<VTKViewer> viewer("Viewer"); + viewer->setActiveScene(scene); - // print UPS - scene->getConfig()->trackFPS = true; - apiutils::printUPS(simManager->getSceneManager(scene)); + // Setup a scene manager to advance the scene in its own thread + imstkNew<SceneManager> sceneManager("Scene Manager"); + sceneManager->setActiveScene(scene); + viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer - simManager->setActiveScene(scene); - simManager->start(SimulationStatus::Paused); + // Add mouse and keyboard controls to the viewer + { + imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice()); + mouseControl->setSceneManager(sceneManager); + viewer->addControl(mouseControl); + + imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice()); + keyControl->setSceneManager(sceneManager); + keyControl->setViewer(viewer); + viewer->addControl(keyControl); + } + + // Start viewer running, scene as paused + sceneManager->requestStatus(ThreadStatus::Paused); + viewer->start(); + } return 0; } @@ -112,37 +136,37 @@ createAndAddPbdObject(std::shared_ptr<Scene> scene, const std::string& tetMeshName) { // Load a sample mesh - auto tetMesh = MeshIO::read(tetMeshName); + std::shared_ptr<PointSet> tetMesh = MeshIO::read(tetMeshName); - auto fluidMesh = std::make_shared<PointSet>(); + imstkNew<PointSet> fluidMesh; fluidMesh->initialize(tetMesh->getInitialVertexPositions()); - auto fluidVisualModel = std::make_shared<VisualModel>(fluidMesh); + imstkNew<VisualModel> fluidVisualModel(fluidMesh.get()); - auto material1 = std::make_shared<RenderMaterial>(); - material1->setDisplayMode(RenderMaterial::DisplayMode::Fluid); - material1->setVertexColor(Color::Red); - material1->setPointSize(12.); - fluidVisualModel->setRenderMaterial(material1); + imstkNew<RenderMaterial> material; + material->setDisplayMode(RenderMaterial::DisplayMode::Fluid); + material->setVertexColor(Color::Red); + material->setPointSize(0.5); + fluidVisualModel->setRenderMaterial(material); - auto deformableObj = std::make_shared<PbdObject>("Dragon"); + imstkNew<PbdObject> deformableObj("Dragon"); deformableObj->addVisualModel(fluidVisualModel); deformableObj->setCollidingGeometry(fluidMesh); deformableObj->setPhysicsGeometry(fluidMesh); - auto pbdModel = std::make_shared<PbdModel>(); + imstkNew<PbdModel> pbdModel; pbdModel->setModelGeometry(fluidMesh); // Configure model - auto pbdParams = std::make_shared<PBDModelConfig>(); + imstkNew<PBDModelConfig> pbdParams; // Constant density constraint with stiffness pbdParams->enableConstraint(PbdConstraint::Type::ConstantDensity, 1.0); // Other parameters pbdParams->m_uniformMassValue = 1.0; - pbdParams->m_gravity = Vec3d(0, -9.8, 0); - pbdParams->m_defaultDt = 0.01; + pbdParams->m_gravity = Vec3d(0.0, -9.8, 0.0); + pbdParams->m_defaultDt = 0.005; pbdParams->m_iterations = 2; pbdParams->collisionParams->m_proximity = 0.01; @@ -263,7 +287,7 @@ createCollidingSurfaceMesh() } } - auto floorMeshColliding = std::make_shared<SurfaceMesh>(); + imstkNew<SurfaceMesh> floorMeshColliding; floorMeshColliding->initialize(vertList, triangles); return floorMeshColliding; } diff --git a/Examples/PBD/PBDString/CMakeLists.txt b/Examples/PBD/PBDString/CMakeLists.txt index 19baab77243a56d243d6cda370571910867dd432..ebfc89726577b3c07b3037e56dffad62a5c853ac 100644 --- a/Examples/PBD/PBDString/CMakeLists.txt +++ b/Examples/PBD/PBDString/CMakeLists.txt @@ -31,4 +31,4 @@ SET_TARGET_PROPERTIES (${PROJECT_NAME} PROPERTIES FOLDER Examples/PBD) #----------------------------------------------------------------------------- # Link libraries to executable #----------------------------------------------------------------------------- -target_link_libraries(${PROJECT_NAME} SimulationManager apiUtilities) +target_link_libraries(${PROJECT_NAME} SimulationManager) diff --git a/Examples/PBD/PBDString/pbdStringExample.cpp b/Examples/PBD/PBDString/pbdStringExample.cpp index 2b3e9e8165f298b815bf2ecae5399072156cb977..1bb01d3baae3c425a7a807714a601c67fc2fed9b 100644 --- a/Examples/PBD/PBDString/pbdStringExample.cpp +++ b/Examples/PBD/PBDString/pbdStringExample.cpp @@ -20,12 +20,18 @@ =========================================================================*/ #include "imstkCamera.h" +#include "imstkKeyboardSceneControl.h" #include "imstkLineMesh.h" +#include "imstkLogger.h" +#include "imstkMouseSceneControl.h" +#include "imstkNew.h" #include "imstkPbdModel.h" #include "imstkPbdObject.h" +#include "imstkRenderMaterial.h" #include "imstkScene.h" #include "imstkSceneManager.h" -#include "imstkSimulationManager.h" +#include "imstkVisualModel.h" +#include "imstkVTKViewer.h" using namespace imstk; @@ -36,7 +42,7 @@ static std::shared_ptr<LineMesh> makeStringGeometry(const Vec3d& pos, const size_t numVerts, const double stringLength) { // Create the geometry - std::shared_ptr<LineMesh> stringGeometry = std::make_shared<LineMesh>(); + imstkNew<LineMesh> stringGeometry; StdVectorOfVec3d vertList; vertList.resize(numVerts); @@ -72,14 +78,14 @@ makePbdString( const double bendStiffness, const Color& color) { - std::shared_ptr<PbdObject> stringObj = std::make_shared<PbdObject>(name); + imstkNew<PbdObject> stringObj(name); // Setup the Geometry std::shared_ptr<LineMesh> stringMesh = makeStringGeometry(pos, numVerts, stringLength); // Setup the Parameters - auto pbdParams = std::make_shared<PBDModelConfig>(); - pbdParams->enableConstraint(PbdConstraint::Type::Distance, 1e7); + imstkNew<PBDModelConfig> pbdParams; + pbdParams->enableConstraint(PbdConstraint::Type::Distance, 1.0e7); pbdParams->enableConstraint(PbdConstraint::Type::Bend, bendStiffness); pbdParams->m_fixedNodeIds = { 0 }; pbdParams->m_uniformMassValue = 5.0; @@ -88,19 +94,19 @@ makePbdString( pbdParams->m_iterations = 5; // Setup the Model - std::shared_ptr<PbdModel> pbdModel = std::make_shared<PbdModel>(); + imstkNew<PbdModel> pbdModel; pbdModel->setModelGeometry(stringMesh); pbdModel->configure(pbdParams); // Setup the VisualModel - std::shared_ptr<RenderMaterial> material = std::make_shared<RenderMaterial>(); + imstkNew<RenderMaterial> material; material->setBackFaceCulling(false); material->setEdgeColor(color); material->setLineWidth(2.0f); material->setPointSize(6.0f); material->setDisplayMode(RenderMaterial::DisplayMode::Wireframe); - std::shared_ptr<VisualModel> visualModel = std::make_shared<VisualModel>(stringMesh); + imstkNew<VisualModel> visualModel(stringMesh); visualModel->setRenderMaterial(material); // Setup the Object @@ -156,8 +162,10 @@ const Color endColor = Color(0.0, 1.0, 0.0); // Color of last string int main() { - auto simManager = std::make_shared<SimulationManager>(); - auto scene = simManager->createNewScene("PBDString"); + // Setup logger (write to file and stdout) + Logger::startLogger(); + + imstkNew<Scene> scene("PBDString"); // Setup N separate strings with varying bend stiffnesses std::vector<std::shared_ptr<PbdObject>> pbdStringObjs = @@ -168,14 +176,13 @@ main() } // Adjust the camera - scene->getCamera()->setFocalPoint(0.0, 0.0, 0.0); - scene->getCamera()->setPosition(0.0, 0.0, 15.0); + scene->getActiveCamera()->setFocalPoint(0.0, 0.0, 0.0); + scene->getActiveCamera()->setPosition(0.0, 0.0, 15.0); // Move the points every frame double t = 0.0; - - auto movePoints = - [&pbdStringObjs, &t](Module* module) + auto movePoints = + [&pbdStringObjs, &t](Event*) { for (unsigned int i = 0; i < pbdStringObjs.size(); i++) { @@ -190,11 +197,35 @@ main() } t += dt; }; - simManager->getSceneManager(scene)->setPostUpdateCallback(movePoints); - // Start - simManager->setActiveScene(scene); - simManager->start(); + // Run the simulation + { + // Setup a viewer to render in its own thread + imstkNew<VTKViewer> viewer("Viewer"); + viewer->setActiveScene(scene); + + // Setup a scene manager to advance the scene in its own thread + imstkNew<SceneManager> sceneManager("Scene Manager"); + sceneManager->setActiveScene(scene); + viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer + connect<Event>(sceneManager, EventType::PostUpdate, movePoints); + + // Add mouse and keyboard controls to the viewer + { + imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice()); + mouseControl->setSceneManager(sceneManager); + viewer->addControl(mouseControl); + + imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice()); + keyControl->setSceneManager(sceneManager); + keyControl->setViewer(viewer); + viewer->addControl(keyControl); + } + + // Start viewer running, scene as paused + sceneManager->requestStatus(ThreadStatus::Paused); + viewer->start(); + } return 0; } \ No newline at end of file diff --git a/Examples/RCM/CMakeLists.txt b/Examples/RCM/CMakeLists.txt index 2ab018c8bc080f7c15440b132cc1d2d696fcb3d4..10814d1f326c1b66b7f90cadc02a73cca99537a4 100644 --- a/Examples/RCM/CMakeLists.txt +++ b/Examples/RCM/CMakeLists.txt @@ -21,7 +21,7 @@ project(Example-RCM) #----------------------------------------------------------------------------- # Create executable #----------------------------------------------------------------------------- -imstk_add_executable(${PROJECT_NAME} RCM.cpp) +imstk_add_executable(${PROJECT_NAME} RCM.cpp bandwidth.h) #----------------------------------------------------------------------------- # Add the target to Examples folder diff --git a/Examples/RCM/RCM.cpp b/Examples/RCM/RCM.cpp index aa24bce918650dc22dd22a7fb965103a30d4b2ef..925dde40158add3ad20858e4c7b0ab2e2e253a3a 100644 --- a/Examples/RCM/RCM.cpp +++ b/Examples/RCM/RCM.cpp @@ -19,14 +19,12 @@ =========================================================================*/ -#include "imstkMeshIO.h" -#include "imstkTetrahedralMesh.h" +#include "bandwidth.h" #include "imstkGeometryUtilities.h" -#include "imstkSurfaceMesh.h" #include "imstkLogger.h" -#include "bandwidth.h" - -#include <thread> +#include "imstkMeshIO.h" +#include "imstkSurfaceMesh.h" +#include "imstkTetrahedralMesh.h" using namespace imstk; @@ -44,9 +42,8 @@ void testRCM(const std::vector<ElemConn>& conn, const size_t numVerts); int main(int argc, char** argv) { - Logger& logger = Logger::getInstance(); - logger.addFileSink("rcm-Example1", "./"); - logger.addStdoutSink(); + // Log to stdout and file + Logger::startLogger(); // a 2D Cartesian mesh { @@ -56,7 +53,7 @@ main(int argc, char** argv) // 3D mesh { - auto tetMesh = std::dynamic_pointer_cast<TetrahedralMesh>(MeshIO::read(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg")); + auto tetMesh = MeshIO::read<TetrahedralMesh>(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg"); const auto numVerts = tetMesh->getNumVertices(); std::cout << "Number of vertices = " << numVerts << std::endl; testRCM(tetMesh->getTetrahedraVertices(), numVerts); @@ -64,7 +61,7 @@ main(int argc, char** argv) // a surface mesh cover { - auto surfMesh = std::dynamic_pointer_cast<SurfaceMesh>(MeshIO::read(iMSTK_DATA_ROOT "/asianDragon/asianDragon.obj")); + auto surfMesh = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/asianDragon/asianDragon.obj"); auto tetMesh = GeometryUtils::createTetrahedralMeshCover(surfMesh, 80, 40, 60); auto conn = tetMesh->getTetrahedraVertices(); auto numVerts = tetMesh->getNumVertices(); diff --git a/Examples/RCM/bandwidth.h b/Examples/RCM/bandwidth.h index 3ddf6f1ed76733c427550bf7c88be31f745e5d99..52a1a7d2e0a01a7e0ee88447bbfc8b8bcf95ae9c 100644 --- a/Examples/RCM/bandwidth.h +++ b/Examples/RCM/bandwidth.h @@ -1,3 +1,29 @@ +/*========================================================================= + + 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 <vector> +#include <unordered_set> + /// /// \brief Build the vertex-to-vertex connectivity of a map // diff --git a/Examples/ReducedFEM/ReducedFEM.cpp b/Examples/ReducedFEM/ReducedFEM.cpp index 5f8c9bfea57234fb6bf4274634e4df150266ec9e..4192ca9f1588ec591875cd89bd534a94ca965dca 100644 --- a/Examples/ReducedFEM/ReducedFEM.cpp +++ b/Examples/ReducedFEM/ReducedFEM.cpp @@ -19,111 +19,171 @@ =========================================================================*/ -#include "imstkTimer.h" -#include "imstkSimulationManager.h" -#include "imstkDeformableObject.h" +#include "imstkFeDeformableObject.h" +#include "imstkRenderMaterial.h" #include "imstkBackwardEuler.h" -#include "imstkNonLinearSystem.h" -#include "imstkNewtonSolver.h" -#include "imstkGaussSeidel.h" #include "imstkPlane.h" #include "imstkTetrahedralMesh.h" #include "imstkMeshIO.h" +#include "imstkMouseSceneControl.h" +#include "imstkNew.h" #include "imstkOneToOneMap.h" -#include "imstkAPIUtilities.h" -#include "imstkConjugateGradient.h" #include "imstkLight.h" #include "imstkCamera.h" #include "imstkReducedStVKBodyModel.h" #include "imstkReducedFeDeformableObject.h" -#include "imstkCollisionGraph.h" #include "imstkSurfaceMesh.h" #include "imstkScene.h" +#include "imstkSceneManager.h" +#include "imstkVisualModel.h" +#include "imstkVTKViewer.h" +#include "imstkKeyboardSceneControl.h" using namespace imstk; +std::shared_ptr<DynamicObject> createAndAddFEDeformable(std::shared_ptr<Scene> scene, std::shared_ptr<TetrahedralMesh> tetMesh); + +// enum to choose difference cases, currently asianDragon or heart +enum Geom +{ + Dragon = 0, + Heart +}; + +struct Input +{ + std::string meshFileName; + std::string cubFileName; + std::string modesFileName; +}; + +Geom geom = Dragon; +// const Geom geom = Heart; +Input input; + /// /// \brief This example demonstrates the soft body simulation -/// using Finite elements +/// using model order reduction (NOR) /// int main() { - // simManager and Scene - auto simConfig = std::make_shared<SimManagerConfig>(); - simConfig->simulationMode = SimulationMode::Rendering; - auto simManager = std::make_shared<SimulationManager>(simConfig); - auto scene = simManager->createNewScene("DeformableBodyFEM"); - scene->getCamera()->setPosition(0, 2.0, 15.0); - - // Load a tetrahedral mesh - // auto tetMesh = MeshIO::read(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg"); - auto tetMesh = MeshIO::read(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg"); + // Setup logger (write to file and stdout) + Logger::startLogger(); + + if (geom == Dragon) + { + input.meshFileName = iMSTK_DATA_ROOT "asianDragon/asianDragon.veg"; + input.cubFileName = iMSTK_DATA_ROOT "asianDragon/asianDragon.cub"; + input.modesFileName = iMSTK_DATA_ROOT "asianDragon/asianDragon.URendering.float"; + } + else if (geom == Heart) + { + input.meshFileName = iMSTK_DATA_ROOT "/heart/heart.veg"; + input.cubFileName = iMSTK_DATA_ROOT "heart/heart.cub"; + input.modesFileName = iMSTK_DATA_ROOT "heart/heart.URendering.float"; + } + + // Construct the scene + imstkNew<SceneConfig> sceneConfig; + sceneConfig->taskParallelizationEnabled = false; + imstkNew<Scene> scene("ReducedFEM", sceneConfig); + + { + std::shared_ptr<Camera> cam = scene->getActiveCamera(); + cam->setPosition(0.0, 2.0, -25.0); + cam->setFocalPoint(0.0, 0.0, 0.0); + + // Load a tetrahedral mesh + auto tetMesh = MeshIO::read<TetrahedralMesh>(input.meshFileName); + CHECK(tetMesh != nullptr) << "Could not read mesh from file."; + + // Scene object 1: fe-FeDeformableObject + std::shared_ptr<DynamicObject> deformableObj = createAndAddFEDeformable(scene, tetMesh); + + // Scene object 2: Plane + imstkNew<Plane> planeGeom; + planeGeom->setWidth(40); + planeGeom->setPosition(0, -6, 0); + imstkNew<CollidingObject> planeObj("Plane"); + planeObj->setVisualGeometry(planeGeom); + planeObj->setCollidingGeometry(planeGeom); + scene->addSceneObject(planeObj); + + // Light + imstkNew<DirectionalLight> light("light"); + light->setFocalPoint(Vec3d(5.0, -8.0, -5.0)); + light->setIntensity(1); + scene->addLight(light); + } - CHECK(tetMesh != nullptr) << "Could not read mesh from file."; - - // Extract the surface mesh - auto surfMesh = std::make_shared<SurfaceMesh>(); - auto volTetMesh = std::dynamic_pointer_cast<TetrahedralMesh>(tetMesh); - - CHECK(volTetMesh != nullptr) << "Dynamic pointer cast from PointSet to TetrahedralMesh failed!"; - - volTetMesh->extractSurfaceMesh(surfMesh, true); - - // Construct a map + // Run the simulation + { + // Setup a viewer to render in its own thread + imstkNew<VTKViewer> viewer("Viewer 1"); + viewer->setActiveScene(scene); + + // Setup a scene manager to advance the scene in its own thread + imstkNew<SceneManager> sceneManager("Scene Manager 1"); + sceneManager->setActiveScene(scene); + viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer + + // Add mouse and keyboard controls to the viewer + { + imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice()); + mouseControl->setSceneManager(sceneManager); + viewer->addControl(mouseControl); + + imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice()); + keyControl->setSceneManager(sceneManager); + keyControl->setViewer(viewer); + viewer->addControl(keyControl); + } + + // Start viewer running, scene as paused + sceneManager->requestStatus(ThreadStatus::Paused); + viewer->start(); + } - // Construct one to one nodal map based on the above meshes - auto oneToOneNodalMap = std::make_shared<OneToOneMap>(tetMesh, surfMesh); + return 0; +} - // Scene object 1: Dragon +std::shared_ptr<DynamicObject> +createAndAddFEDeformable(std::shared_ptr<Scene> scene, + std::shared_ptr<TetrahedralMesh> tetMesh) +{ + imstkNew<SurfaceMesh> surfMesh; + tetMesh->extractSurfaceMesh(surfMesh, true); // Configure dynamic model - auto dynaModel = std::make_shared<ReducedStVK>(); - - //dynaModel->configure(iMSTK_DATA_ROOT "/asianDragon/asianDragon.config"); - - auto config = std::make_shared<ReducedStVKConfig>(); - // config->m_fixedNodeIds = { 51, 127, 178 }; - config->m_cubicPolynomialFilename = iMSTK_DATA_ROOT "/asianDragon/asianDragon.cub"; - config->m_modesFileName = iMSTK_DATA_ROOT "/asianDragon/asianDragon.URendering.float"; + imstkNew<ReducedStVK> dynaModel; + imstkNew<ReducedStVKConfig> config; + config->m_cubicPolynomialFilename = input.cubFileName; + config->m_modesFileName = input.modesFileName; dynaModel->configure(config); + //dynaModel->configure(iMSTK_DATA_ROOT "/asianDragon/asianDragon.config"); dynaModel->setTimeStepSizeType(TimeSteppingType::Fixed); - dynaModel->setModelGeometry(volTetMesh); - auto timeIntegrator = std::make_shared<BackwardEuler>(0.01);// Create and add Backward Euler time integrator + dynaModel->setModelGeometry(tetMesh); + imstkNew<BackwardEuler> timeIntegrator(0.01); // Create and add Backward Euler time integrator dynaModel->setTimeIntegrator(timeIntegrator); - auto material = std::make_shared<RenderMaterial>(); - material->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface); - auto surfMeshModel = std::make_shared<VisualModel>(surfMesh); - surfMeshModel->setRenderMaterial(material); + imstkNew<RenderMaterial> mat; + mat->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface); + mat->setPointSize(10.); + mat->setLineWidth(4.); + mat->setEdgeColor(Color::Orange); + imstkNew<VisualModel> surfMeshModel(surfMesh.get()); + surfMeshModel->setRenderMaterial(mat); - // Scene Object - auto deformableObj = std::make_shared<ReducedFeDeformableObject>("Dragon"); + // Scene object 1: Dragon + imstkNew<ReducedFeDeformableObject> deformableObj("Dragon"); deformableObj->addVisualModel(surfMeshModel); - deformableObj->setPhysicsGeometry(volTetMesh); - deformableObj->setPhysicsToVisualMap(oneToOneNodalMap); //assign the computed map + deformableObj->setPhysicsGeometry(tetMesh); + // Map simulated geometry to visual + deformableObj->setPhysicsToVisualMap(std::make_shared<OneToOneMap>(tetMesh, surfMesh)); deformableObj->setDynamicalModel(dynaModel); scene->addSceneObject(deformableObj); - // Scene object 2: Plane - auto planeGeom = std::make_shared<Plane>(); - planeGeom->setWidth(40); - planeGeom->setPosition(0, -6, 0); - auto planeObj = std::make_shared<CollidingObject>("Plane"); - planeObj->setVisualGeometry(planeGeom); - planeObj->setCollidingGeometry(planeGeom); - scene->addSceneObject(planeObj); - - // Light - auto light = std::make_shared<DirectionalLight>("light"); - light->setFocalPoint(Vec3d(5, -8, -5)); - light->setIntensity(1); - scene->addLight(light); - - // Run the simulation - simManager->setActiveScene(scene); - simManager->start(SimulationStatus::Paused); - - return 0; + return deformableObj; } diff --git a/Examples/Rendering/RenderingExample.cpp b/Examples/Rendering/RenderingExample.cpp index cf9dcf2a0d03bde879b8a8ffbb74805c562ded8d..4d3b7d2fc65e65783050173d5d99e0213e455a39 100644 --- a/Examples/Rendering/RenderingExample.cpp +++ b/Examples/Rendering/RenderingExample.cpp @@ -19,14 +19,21 @@ =========================================================================*/ -#include "imstkSimulationManager.h" #include "imstkAPIUtilities.h" -#include "imstkVisualObjectImporter.h" -#include "imstkIBLProbe.h" #include "imstkCamera.h" -#include "imstkMeshIO.h" +#include "imstkIBLProbe.h" +#include "imstkKeyboardSceneControl.h" #include "imstkLight.h" +#include "imstkMeshIO.h" +#include "imstkMouseSceneControl.h" +#include "imstkNew.h" +#include "imstkRenderMaterial.h" #include "imstkScene.h" +#include "imstkSceneManager.h" +#include "imstkSceneObject.h" +#include "imstkSurfaceMesh.h" +#include "imstkVisualModel.h" +#include "imstkVTKViewer.h" using namespace imstk; @@ -37,105 +44,127 @@ using namespace imstk; int main() { - // simManager and Scene - auto simManager = std::make_shared<SimulationManager>(); - auto scene = simManager->createNewScene("Rendering"); - - // Add IBL Probe - auto globalIBLProbe = std::make_shared<IBLProbe>( - iMSTK_DATA_ROOT "/IBL/roomIrradiance.dds", - iMSTK_DATA_ROOT "/IBL/roomRadiance.dds", - iMSTK_DATA_ROOT "/IBL/roomBRDF.png"); - scene->setGlobalIBLProbe(globalIBLProbe); - - // Head mesh + imstkNew<Scene> scene("Rendering"); + { + // Add IBL Probe + imstkNew<IBLProbe> globalIBLProbe( + iMSTK_DATA_ROOT "/IBL/roomIrradiance.dds", + iMSTK_DATA_ROOT "/IBL/roomRadiance.dds", + iMSTK_DATA_ROOT "/IBL/roomBRDF.png"); + scene->setGlobalIBLProbe(globalIBLProbe); + + // Head mesh #ifdef iMSTK_USE_Vulkan - auto headObject = VisualObjectImporter::importVisualObject( - "head", iMSTK_DATA_ROOT "/head/head_revised.obj", - iMSTK_DATA_ROOT "/head/", 1, Vec3d(0, 0, 0), "dds"); + auto headObject = VisualObjectImporter::importVisualObject( + "head", iMSTK_DATA_ROOT "/head/head_revised.obj", + iMSTK_DATA_ROOT "/head/", 1, Vec3d(0, 0, 0), "dds"); #else - /*auto headObject = VisualObjectImporter::importVisualObject( - "head", - iMSTK_DATA_ROOT "/head/head_revised.obj", - iMSTK_DATA_ROOT "/head/");*/ - - auto surfaceMesh = MeshIO::read(iMSTK_DATA_ROOT "/head/head_revised.obj"); - - auto material = std::make_shared<RenderMaterial>(); - material->setDisplayMode(RenderMaterial::DisplayMode::Surface); - material->setShadingModel(RenderMaterial::ShadingModel::PBR); - auto headDiffuseTexture = std::make_shared<Texture>(iMSTK_DATA_ROOT "head/HeadTexture_BaseColor.png", Texture::Type::Diffuse); - auto headNormalTexture = std::make_shared<Texture>(iMSTK_DATA_ROOT "head/HeadTexture_Normal.png", Texture::Type::Normal); - auto headAoTexture = std::make_shared<Texture>(iMSTK_DATA_ROOT "head/HeadTexture_AO.png", Texture::Type::AmbientOcclusion); - - material->addTexture(headDiffuseTexture); - material->addTexture(headNormalTexture); - material->addTexture(headAoTexture); - - auto surfMeshModel = std::make_shared<VisualModel>(surfaceMesh); - surfMeshModel->setRenderMaterial(material); - - auto headObject = std::make_shared<VisualObject>("head"); - headObject->addVisualModel(surfMeshModel); - - // Head material with textures - /* auto headNormalTexture = std::make_shared<Texture>(iMSTK_DATA_ROOT "head/HeadTexture_Normal.jpg", Texture::Type::Normal); - auto headDiffuseTexture = std::make_shared<Texture>(iMSTK_DATA_ROOT "head/HeadTexture_BaseColor.jpg", Texture::Type::Diffuse); - auto headMaterial = headObject->getVisualModel()->getRenderMaterial(); - headMaterial->setShadingModel(RenderMaterial::ShadingModel::PBR); - headMaterial->addTexture(headNormalTexture); - headMaterial->addTexture(headDiffuseTexture);*/ - - //headMaterial->addTexture(headDiffuseTexture); + /*auto headObject = VisualObjectImporter::importVisualObject( + "head", + iMSTK_DATA_ROOT "/head/head_revised.obj", + iMSTK_DATA_ROOT "/head/");*/ + + auto surfaceMesh = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/head/head_revised.obj"); + + imstkNew<RenderMaterial> material; + material->setDisplayMode(RenderMaterial::DisplayMode::Surface); + material->setShadingModel(RenderMaterial::ShadingModel::PBR); + imstkNew<Texture> headDiffuseTexture(iMSTK_DATA_ROOT "head/HeadTexture_BaseColor.png", Texture::Type::Diffuse); + imstkNew<Texture> headNormalTexture(iMSTK_DATA_ROOT "head/HeadTexture_Normal.png", Texture::Type::Normal); + imstkNew<Texture> headAoTexture(iMSTK_DATA_ROOT "head/HeadTexture_AO.png", Texture::Type::AmbientOcclusion); + + material->addTexture(headDiffuseTexture); + material->addTexture(headNormalTexture); + material->addTexture(headAoTexture); + + imstkNew<VisualModel> surfMeshModel(surfaceMesh); + surfMeshModel->setRenderMaterial(material); + + imstkNew<VisualObject> headObject("head"); + headObject->addVisualModel(surfMeshModel); + + // Head material with textures + /* auto headNormalTexture = std::make_shared<Texture>(iMSTK_DATA_ROOT "head/HeadTexture_Normal.jpg", Texture::Type::Normal); + auto headDiffuseTexture = std::make_shared<Texture>(iMSTK_DATA_ROOT "head/HeadTexture_BaseColor.jpg", Texture::Type::Diffuse); + auto headMaterial = headObject->getVisualModel()->getRenderMaterial(); + headMaterial->setShadingModel(RenderMaterial::ShadingModel::PBR); + headMaterial->addTexture(headNormalTexture); + headMaterial->addTexture(headDiffuseTexture);*/ + + //headMaterial->addTexture(headDiffuseTexture); #endif - scene->addSceneObject(headObject); + scene->addSceneObject(headObject); - // Position camera - auto cam = scene->getCamera(); - cam->setPosition(0, 0.25, 0.6); - cam->setFocalPoint(0, 0.25, 0); + // Position camera + scene->getActiveCamera()->setPosition(0.0, 0.25, 0.6); + scene->getActiveCamera()->setFocalPoint(0.0, 0.25, 0.0); - // Lights - auto directionalLight = std::make_shared<DirectionalLight>("DirectionalLight"); - directionalLight->setIntensity(4); - directionalLight->setColor(Color(1.0, 0.95, 0.8)); - directionalLight->setCastsShadow(true); - directionalLight->setShadowRange(1.5); - scene->addLight(directionalLight); + // Lights + imstkNew<DirectionalLight> dirLight("DirectionalLight"); + dirLight->setIntensity(4.0); + dirLight->setColor(Color(1.0, 0.95, 0.8)); + dirLight->setCastsShadow(true); + dirLight->setShadowRange(1.5); + scene->addLight(dirLight); - auto pointLight = std::make_shared<PointLight>("PointLight"); - pointLight->setIntensity(0.1); - pointLight->setPosition(0.1, 0.2, 0.5); - scene->addLight(pointLight); + imstkNew<PointLight> pointLight("PointLight"); + pointLight->setIntensity(0.1); + pointLight->setPosition(0.1, 0.2, 0.5); + scene->addLight(pointLight); #ifdef iMSTK_USE_Vulkan - // Sphere - auto sphereObj = apiutils::createVisualAnalyticalSceneObject(Geometry::Type::Sphere, scene, "VisualSphere", 0.025); - auto sphereMaterial = std::make_shared<RenderMaterial>(); - auto sphereMesh = sphereObj->getVisualGeometry(); - sphereMesh->translate(0.1, 0.2, 0.5); - sphereMaterial->setEmissivity(2); - sphereMaterial->setCastsShadows(false); - sphereObj->getVisualModel(0)->setRenderMaterial(sphereMaterial); + // Sphere + auto sphereObj = apiutils::createVisualAnalyticalSceneObject(Geometry::Type::Sphere, scene, "VisualSphere", 0.025); + imstkNew<RenderMaterial> sphereMaterial; + auto sphereMesh = sphereObj->getVisualGeometry(); + sphereMesh->translate(0.1, 0.2, 0.5); + sphereMaterial->setEmissivity(2); + sphereMaterial->setCastsShadows(false); + sphereObj->getVisualModel(0)->setRenderMaterial(sphereMaterial); #endif - // Plane - auto planeObj = apiutils::createVisualAnalyticalSceneObject(Geometry::Type::Plane, scene, "VisualPlane", 10); - auto planeMaterial = std::make_shared<RenderMaterial>(); - planeMaterial->setColor(Color::LightGray); - planeObj->getVisualModel(0)->setRenderMaterial(planeMaterial); + // Plane + auto planeObj = apiutils::createVisualAnalyticalSceneObject(Geometry::Type::Plane, scene, "VisualPlane", 10); + imstkNew<RenderMaterial> planeMaterial; + planeMaterial->setColor(Color::LightGray); + planeObj->getVisualModel(0)->setRenderMaterial(planeMaterial); #ifdef iMSTK_USE_Vulkan - auto viewer = std::dynamic_pointer_cast<VulkanViewer>(simManager->getViewer()); - viewer->setResolution(1000, 800); - viewer->disableVSync(); - //viewer->enableFullscreen(); + auto viewer = std::dynamic_pointer_cast<VulkanViewer>(simManager->getViewer()); + viewer->setResolution(1000, 800); + viewer->disableVSync(); + //viewer->enableFullscreen(); #endif - - // Run - simManager->setActiveScene(scene); - simManager->start(SimulationStatus::Paused); + } + + // Run the simulation + { + // Setup a viewer to render in its own thread + imstkNew<VTKViewer> viewer("Viewer"); + viewer->setActiveScene(scene); + + // Setup a scene manager to advance the scene in its own thread + imstkNew<SceneManager> sceneManager("Scene Manager"); + sceneManager->setActiveScene(scene); + viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer + + // Add mouse and keyboard controls to the viewer + { + imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice()); + mouseControl->setSceneManager(sceneManager); + viewer->addControl(mouseControl); + + imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice()); + keyControl->setSceneManager(sceneManager); + keyControl->setViewer(viewer); + viewer->addControl(keyControl); + } + + // Start viewer running, scene as paused + sceneManager->requestStatus(ThreadStatus::Paused); + viewer->start(); + } return 0; } diff --git a/Examples/RigidBodyDynamics/RigidBodyDynamicsExample.cpp b/Examples/RigidBodyDynamics/RigidBodyDynamicsExample.cpp index 44c07c071ce9086dda1d72b8a90c7f8310a129a6..7dec42133fbf8fe747ba3d000d846cb208112311 100644 --- a/Examples/RigidBodyDynamics/RigidBodyDynamicsExample.cpp +++ b/Examples/RigidBodyDynamics/RigidBodyDynamicsExample.cpp @@ -19,47 +19,48 @@ =========================================================================*/ -#include "imstkSimulationManager.h" -#include "imstkCollisionGraph.h" -#include "imstkRigidObject.h" -#include "imstkRigidBodyModel.h" -#include "imstkSceneObject.h" -#include "imstkTetrahedralMesh.h" -#include "imstkLight.h" #include "imstkCamera.h" #include "imstkCube.h" -#include "imstkPlane.h" -#include "imstkSphere.h" -#include "imstkMeshIO.h" #include "imstkIsometricMap.h" +#include "imstkKeyboardSceneControl.h" +#include "imstkLight.h" +#include "imstkLogger.h" +#include "imstkMeshIO.h" +#include "imstkMouseSceneControl.h" +#include "imstkNew.h" +#include "imstkPlane.h" +#include "imstkRenderMaterial.h" +#include "imstkRigidBodyModel.h" +#include "imstkRigidObject.h" #include "imstkScene.h" +#include "imstkSceneManager.h" +#include "imstkSphere.h" +#include "imstkSurfaceMesh.h" +#include "imstkTetrahedralMesh.h" +#include "imstkVisualModel.h" +#include "imstkVTKViewer.h" using namespace imstk; std::shared_ptr<imstk::RigidObject> -addMeshRigidObject(const std::string& name, std::shared_ptr<Scene> scene, Vec3d pos) +makeMeshRigidObject(const std::string& name, const Vec3d& pos) { // create cube object - auto meshObj = std::make_shared<RigidObject>(name); + imstkNew<RigidObject> meshObj(name); // Load a tetrahedral mesh - auto tetMesh = imstk::MeshIO::read(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg"); - - CHECK(tetMesh != nullptr) << "Could not read mesh from file."; + auto tetMesh = imstk::MeshIO::read<TetrahedralMesh>(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg"); // Extract the surface mesh - auto surfMesh = std::make_shared<SurfaceMesh>(); - auto volTetMesh = std::dynamic_pointer_cast<TetrahedralMesh>(tetMesh); + imstkNew<SurfaceMesh> surfMesh; - CHECK(volTetMesh != nullptr) << "Dynamic pointer cast from PointSet to TetrahedralMesh failed!"; - - volTetMesh->scale(15., Geometry::TransformType::ApplyToData); - volTetMesh->translate(pos, Geometry::TransformType::ApplyToData); - volTetMesh->extractSurfaceMesh(surfMesh, true); + tetMesh->scale(15., Geometry::TransformType::ApplyToData); + tetMesh->translate(pos, Geometry::TransformType::ApplyToData); + tetMesh->extractSurfaceMesh(surfMesh, true); // add visual model - auto renderModel = std::make_shared<VisualModel>(surfMesh); - auto mat = std::make_shared<RenderMaterial>(); + imstkNew<VisualModel> renderModel(surfMesh.get()); + imstkNew<RenderMaterial> mat; mat->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface); mat->setLineWidth(2.); mat->setColor(Color::Green); @@ -67,36 +68,33 @@ addMeshRigidObject(const std::string& name, std::shared_ptr<Scene> scene, Vec3d meshObj->addVisualModel(renderModel); // add dynamic model - auto rigidModel = std::make_shared<RigidBodyModel>(); - auto rigidProp = std::make_shared<RigidBodyConfig>(); + imstkNew<RigidBodyModel> rigidModel; + imstkNew<RigidBodyConfig> rigidProp; rigidProp->m_rigidBodyType = RigidBodyType::Kinematic; rigidModel->configure(rigidProp); rigidModel->setModelGeometry(surfMesh); meshObj->setPhysicsGeometry(surfMesh); meshObj->setDynamicalModel(rigidModel); - // add cube to scene - scene->addSceneObject(meshObj); return meshObj; } std::shared_ptr<imstk::RigidObject> -addCubeRigidObject(std::string& name, std::shared_ptr<Scene> scene, Vec3d pos, const bool isStatic = false) +makeCubeRigidObject(std::string& name, const Vec3d& pos, const bool isStatic = false) { - // create cube object - auto cubeObj = std::make_shared<RigidObject>(name); + // Create cube object + imstkNew<RigidObject> cubeObj(name); - // Create Cube object - auto cubeGeom = std::make_shared<Cube>(); - cubeGeom->setWidth(20.); + // Create cube geometry + imstkNew<Cube> cubeGeom; + cubeGeom->setWidth(20.0); cubeGeom->translate(pos); - // cube visual model - auto mesh = imstk::MeshIO::read(iMSTK_DATA_ROOT "/asianDragon/asianDragon.obj"); - auto SurfaceMesh = std::dynamic_pointer_cast<imstk::SurfaceMesh>(mesh); - SurfaceMesh->scale(5., Geometry::TransformType::ApplyToData); - auto renderModel = std::make_shared<VisualModel>(cubeGeom); - auto mat = std::make_shared<RenderMaterial>(); + // Create cube VisualModel + auto mesh = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/asianDragon/asianDragon.obj"); + mesh->scale(5.0, Geometry::TransformType::ApplyToData); + imstkNew<VisualModel> renderModel(cubeGeom.get()); + imstkNew<RenderMaterial> mat; mat->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface); mat->setLineWidth(2.); mat->setColor(Color::Orange); @@ -105,11 +103,11 @@ addCubeRigidObject(std::string& name, std::shared_ptr<Scene> scene, Vec3d pos, c auto rigidMap = std::make_shared<IsometricMap>(); rigidMap->setMaster(cubeGeom); - rigidMap->setSlave(SurfaceMesh); + rigidMap->setSlave(mesh); - // cube dynamic model - auto rigidModel = std::make_shared<RigidBodyModel>(); - auto rigidProp = std::make_shared<RigidBodyConfig>(); + // Create cube DynamicalModel + imstkNew<RigidBodyModel> rigidModel; + imstkNew<RigidBodyConfig> rigidProp; rigidProp->m_dynamicFriction = 0.01; rigidProp->m_restitution = 0.01; rigidProp->m_staticFriction = 0.005; @@ -118,93 +116,113 @@ addCubeRigidObject(std::string& name, std::shared_ptr<Scene> scene, Vec3d pos, c rigidModel->setModelGeometry(cubeGeom); cubeObj->setDynamicalModel(rigidModel); - //cubeObj->setPhysicsToVisualMap(rigidMap); - - // add cube to scene - scene->addSceneObject(cubeObj); return cubeObj; } -void -addPlaneRigidObject(std::shared_ptr<Scene> scene) +std::shared_ptr<RigidObject> +makePlaneRigidObject() { // create plane object - auto planeObj = std::make_shared<RigidObject>("Plane"); + imstkNew<RigidObject> planeObj("Plane"); - auto planeGeom = std::make_shared<Plane>(); - planeGeom->setWidth(400.); + imstkNew<Plane> planeGeom; + planeGeom->setWidth(400.0); // visual model - auto renderModel2 = std::make_shared<VisualModel>(planeGeom); - renderModel2->setRenderMaterial(std::make_shared<RenderMaterial>()); - planeObj->addVisualModel(renderModel2); + imstkNew<VisualModel> renderModel(planeGeom.get()); + renderModel->setRenderMaterial(std::make_shared<RenderMaterial>()); + planeObj->addVisualModel(renderModel); // dynamic model - auto rigidModel2 = std::make_shared<RigidBodyModel>(); - auto rigidProp2 = std::make_shared<RigidBodyConfig>(); - rigidModel2->configure(rigidProp2); - rigidModel2->setModelGeometry(planeGeom); - planeObj->setDynamicalModel(rigidModel2); + imstkNew<RigidBodyModel> rigidModel; + imstkNew<RigidBodyConfig> rigidProp; + rigidModel->configure(rigidProp); + rigidModel->setModelGeometry(planeGeom); + planeObj->setDynamicalModel(rigidModel); - scene->addSceneObject(planeObj); + return planeObj; } -void -addSphereRigidObject(std::shared_ptr<Scene> scene, Vec3d t = Vec3d(0., 0., 0.)) +std::shared_ptr<RigidObject> +makeSphereRigidObject(const Vec3d& t = Vec3d(0.0, 0.0, 0.0)) { // create cube object - auto sphereObj = std::make_shared<RigidObject>("Sphere"); + imstkNew<RigidObject> sphereObj("Sphere"); // Create Cube object - auto sphereGeom = std::make_shared<Sphere>(); - sphereGeom->setRadius(10.); + imstkNew<Sphere> sphereGeom; + sphereGeom->setRadius(10.0); sphereGeom->translate(t); // cube visual model - auto renderModel = std::make_shared<VisualModel>(sphereGeom); + imstkNew<VisualModel> renderModel(sphereGeom.get()); renderModel->setRenderMaterial(std::make_shared<RenderMaterial>()); sphereObj->addVisualModel(renderModel); // cube dynamic model - auto rigidModel3 = std::make_shared<RigidBodyModel>(); - auto rigidProp = std::make_shared<RigidBodyConfig>(); + imstkNew<RigidBodyModel> rigidModel; + imstkNew<RigidBodyConfig> rigidProp; rigidProp->m_rigidBodyType = RigidBodyType::Dynamic; - rigidModel3->configure(rigidProp); - rigidModel3->setModelGeometry(sphereGeom); - sphereObj->setDynamicalModel(rigidModel3); + rigidModel->configure(rigidProp); + rigidModel->setModelGeometry(sphereGeom); + sphereObj->setDynamicalModel(rigidModel); - // add cube to scene - scene->addSceneObject(sphereObj); + return sphereObj; } int main() { - //simManager and Scene - auto simManager = std::make_shared<SimulationManager>(); - auto scene = simManager->createNewScene("Rigid Body Dynamics"); + // Write log to stdout and file + Logger::startLogger(); - for (int i = 0; i < 1; ++i) + imstkNew<Scene> scene("Rigid Body Dynamics"); { - addCubeRigidObject(std::string("cube_").append(std::to_string(i)), scene, Vec3d(0., 150. + i * 21, 0.)); + for (int i = 0; i < 1; i++) + { + scene->addSceneObject(makeCubeRigidObject(std::string("cube_").append(std::to_string(i)), Vec3d(0.0, 150.0 + i * 21.0, 0.0))); + } + + scene->addSceneObject(makePlaneRigidObject()); + scene->addSceneObject(makeSphereRigidObject(Vec3d(0.0, 200.0, 0.0))); + scene->addSceneObject(makeMeshRigidObject(std::string("dragon"), Vec3d(0.0, 30.0, 0.0))); + + // Set Camera configuration + scene->getActiveCamera()->setPosition(Vec3d(300.0, 300.0, 300.0)); + + // Light + imstkNew<DirectionalLight> light("light"); + light->setIntensity(1.0); + scene->addLight(light); } - addPlaneRigidObject(scene); - addSphereRigidObject(scene, Vec3d(0., 200, 0.)); - auto rigidObj = addMeshRigidObject(std::string("dragon"), scene, Vec3d(0., 30., 0.)); - - // Set Camera configuration - auto cam = scene->getCamera(); - cam->setPosition(Vec3d(300, 300, 300)); - - // Light - auto light = std::make_shared<DirectionalLight>("light"); - light->setIntensity(1); - scene->addLight(light); - - // Run - simManager->setActiveScene(scene); - simManager->start(SimulationStatus::Paused); + // Run the simulation + { + // Setup a viewer to render in its own thread + imstkNew<VTKViewer> viewer("Viewer"); + viewer->setActiveScene(scene); + + // Setup a scene manager to advance the scene in its own thread + imstkNew<SceneManager> sceneManager("Scene Manager"); + sceneManager->setActiveScene(scene); + viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer + + // Add mouse and keyboard controls to the viewer + { + imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice()); + mouseControl->setSceneManager(sceneManager); + viewer->addControl(mouseControl); + + imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice()); + keyControl->setSceneManager(sceneManager); + keyControl->setViewer(viewer); + viewer->addControl(keyControl); + } + + // Start viewer running, scene as paused + sceneManager->requestStatus(ThreadStatus::Paused); + viewer->start(); + } return 0; } diff --git a/Examples/RigidBodyDynamics2/CMakeLists.txt b/Examples/RigidBodyDynamics2/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..5c875c9edcdc43fe62f9b2f6e236847969060c43 --- /dev/null +++ b/Examples/RigidBodyDynamics2/CMakeLists.txt @@ -0,0 +1,34 @@ +########################################################################### +# +# Copyright (c) Kitware, Inc. +# +# 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. +# +########################################################################### + +project(Example-RigidBodyDynamics2) + +#----------------------------------------------------------------------------- +# Create executable +#----------------------------------------------------------------------------- +imstk_add_executable(${PROJECT_NAME} RigidBodyDynamicsExample2.cpp) + +#----------------------------------------------------------------------------- +# Add the target to Examples folder +#----------------------------------------------------------------------------- +SET_TARGET_PROPERTIES (${PROJECT_NAME} PROPERTIES FOLDER Examples) + +#----------------------------------------------------------------------------- +# Link libraries to executable +#----------------------------------------------------------------------------- +target_link_libraries(${PROJECT_NAME} SimulationManager Filtering) diff --git a/Examples/RigidBodyDynamics2/RigidBodyDynamicsExample2.cpp b/Examples/RigidBodyDynamics2/RigidBodyDynamicsExample2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dce0234dfa7d9aeeec9ef0fd0cfc53ae28d4fae6 --- /dev/null +++ b/Examples/RigidBodyDynamics2/RigidBodyDynamicsExample2.cpp @@ -0,0 +1,237 @@ +/*========================================================================= + + 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 "imstkCamera.h" +#include "imstkCollisionGraph.h" +#include "imstkCompositeImplicitGeometry.h" +#include "imstkCube.h" +#include "imstkGeometryUtilities.h" +#include "imstkImplicitGeometryToImageData.h" +#include "imstkKeyboardDeviceClient.h" +#include "imstkKeyboardSceneControl.h" +#include "imstkLight.h" +#include "imstkLogger.h" +#include "imstkMouseSceneControl.h" +#include "imstkNew.h" +#include "imstkPlane.h" +#include "imstkRbdConstraint.h" +#include "imstkRenderMaterial.h" +#include "imstkRigidBodyCH.h" +#include "imstkRigidBodyModel2.h" +#include "imstkRigidObject2.h" +#include "imstkRigidObjectCollisionPair.h" +#include "imstkScene.h" +#include "imstkSceneManager.h" +#include "imstkSphere.h" +#include "imstkSurfaceMesh.h" +#include "imstkSurfaceMeshFlyingEdges.h" +#include "imstkSurfaceMeshSubdivide.h" +#include "imstkVisualModel.h" +#include "imstkVTKViewer.h" + +using namespace imstk; +using namespace imstk::expiremental; + +/// +/// \brief This example demonstrates a rigid body model. The rigid body model uses +/// an implicit model to solve all bodies together. This means they all share a model. +/// Also implements key controls in a lambda +/// +int +main() +{ + // Write log to stdout and file + Logger::startLogger(); + + imstkNew<Scene> scene("Rigid Body Dynamics"); + imstkNew<RigidObject2> cubeObj("Cube"); + { + // This model is shared among interacting rigid bodies + imstkNew<RigidBodyModel2> rbdModel; + rbdModel->getConfig()->m_dt = 0.005; + rbdModel->getConfig()->m_maxNumIterations = 20; + + // Create the first rbd, plane floor + imstkNew<RigidObject2> planeObj("Plane"); + { + // Subtract the sphere from the plane to make a crater + imstkNew<Plane> planeGeom; + planeGeom->setWidth(40.0); + imstkNew<Sphere> sphereGeom; + sphereGeom->setRadius(25.0); + sphereGeom->setPosition(0.0, 10.0, 0.0); + imstkNew<CompositeImplicitGeometry> compGeom; + compGeom->addImplicitGeometry(planeGeom, CompositeImplicitGeometry::GeometryBoolType::Union); + compGeom->addImplicitGeometry(sphereGeom, CompositeImplicitGeometry::GeometryBoolType::Difference); + + // Rasterize the SDF into an image + imstkNew<ImplicitGeometryToImageData> toImage; + toImage->setInputGeometry(compGeom); + Vec6d bounds; + bounds[0] = -20.0; + bounds[1] = 20.0; + bounds[2] = -20.0; + bounds[3] = 20.0; + bounds[4] = -20.0; + bounds[5] = 20.0; + toImage->setBounds(bounds); + toImage->setDimensions(Vec3i(80, 80, 80)); + toImage->update(); + + // Extract surface + imstkNew<SurfaceMeshFlyingEdges> toSurfMesh; + toSurfMesh->setInputImage(toImage->getOutputImage()); + toSurfMesh->update(); + + // Create the visual model + imstkNew<VisualModel> visualModel(toSurfMesh->getOutputMesh()); + + // Create the object + planeObj->addVisualModel(visualModel); + planeObj->setPhysicsGeometry(compGeom); + planeObj->setCollidingGeometry(compGeom); + planeObj->setDynamicalModel(rbdModel); + planeObj->getRigidBody()->m_isStatic = true; + planeObj->getRigidBody()->m_mass = 100.0; + + scene->addSceneObject(planeObj); + } + + // Create surface mesh cube (so we can use pointset for point->implicit collision) + { + imstkNew<Cube> cubeGeom; + cubeGeom->setWidth(4.0); + std::shared_ptr<SurfaceMesh> surfMesh = GeometryUtils::toCubeSurfaceMesh(cubeGeom); + + imstkNew<SurfaceMeshSubdivide> subdivide; + subdivide->setInputMesh(surfMesh); + subdivide->setNumberOfSubdivisions(1); + subdivide->update(); + + // Create the visual model + imstkNew<VisualModel> visualModel(subdivide->getOutputMesh()); + imstkNew<RenderMaterial> mat; + mat->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface); + mat->setLineWidth(2.0); + mat->setColor(Color::Orange); + visualModel->setRenderMaterial(mat); + + // Create the cube rigid object + cubeObj->setDynamicalModel(rbdModel); + cubeObj->setPhysicsGeometry(subdivide->getOutputMesh()); + cubeObj->setCollidingGeometry(subdivide->getOutputMesh()); + cubeObj->addVisualModel(visualModel); + cubeObj->getRigidBody()->m_mass = 100.0; + cubeObj->getRigidBody()->m_initPos = Vec3d(0.0, 8.0, 0.0); + cubeObj->getRigidBody()->m_initOrientation = Quatd(Rotd(0.4, Vec3d(1.0, 0.0, 0.0))); + cubeObj->getRigidBody()->setInertiaFromPointSet(subdivide->getOutputMesh(), 0.001, true); + + scene->addSceneObject(cubeObj); + } + + auto rbdInteraction = std::make_shared<RigidObjectCollisionPair>(cubeObj, planeObj, CollisionDetection::Type::PointSetToImplicit); + std::dynamic_pointer_cast<RigidBodyCH>(rbdInteraction->getCollisionHandlingA())->setUseFriction(false); + scene->getCollisionGraph()->addInteraction(rbdInteraction); + scene->getActiveCamera()->setPosition(0.0, 40.0, 40.0); + + // Light + imstkNew<DirectionalLight> light("light"); + light->setIntensity(1.0); + scene->addLight(light); + } + + // Run the simulation + { + // Setup a viewer to render in its own thread + imstkNew<VTKViewer> viewer("Viewer"); + viewer->setActiveScene(scene); + + // Setup a scene manager to advance the scene in its own thread + imstkNew<SceneManager> sceneManager("Scene Manager"); + sceneManager->setActiveScene(scene); + viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer + + // Add mouse and keyboard controls to the viewer + { + imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice()); + mouseControl->setSceneManager(sceneManager); + viewer->addControl(mouseControl); + + imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice()); + keyControl->setSceneManager(sceneManager); + keyControl->setViewer(viewer); + viewer->addControl(keyControl); + } + + LOG(INFO) << "Cube Controls:"; + LOG(INFO) << "----------------------------------------------------------------------"; + LOG(INFO) << " | i - forward movement"; + LOG(INFO) << " | j - left movement"; + LOG(INFO) << " | l - right movement"; + LOG(INFO) << " | k - backwards movement"; + LOG(INFO) << " | u - rotate left"; + LOG(INFO) << " | o - rotate right"; + + // Not perfectly thread safe movement lambda, ijkl movement instead of wasd because d is already used + std::shared_ptr<KeyboardDeviceClient> keyDevice = viewer->getKeyboardDevice(); + const Vec3d dx = scene->getActiveCamera()->getPosition() - scene->getActiveCamera()->getFocalPoint(); + connect<Event>(sceneManager, EventType::PreUpdate, [&](Event*) + { + Vec3d extForce = Vec3d(0.0, 0.0, 0.0); + Vec3d extTorque = Vec3d(0.0, 0.0, 0.0); + // If w down, move forward + if (keyDevice->getButton('i') == KEY_PRESS) + { + extForce += Vec3d(0.0, 0.0, -40.0); + } + if (keyDevice->getButton('k') == KEY_PRESS) + { + extForce += Vec3d(0.0, 0.0, 40.0); + } + if (keyDevice->getButton('j') == KEY_PRESS) + { + extForce += Vec3d(-40.0, 0.0, 0.0); + } + if (keyDevice->getButton('l') == KEY_PRESS) + { + extForce += Vec3d(40.0, 0.0, 0.0); + } + if (keyDevice->getButton('u') == KEY_PRESS) + { + extTorque += Vec3d(0.0, 1.5, 0.0); + } + if (keyDevice->getButton('o') == KEY_PRESS) + { + extTorque += Vec3d(0.0, -1.5, 0.0); + } + *cubeObj->getRigidBody()->m_force = extForce; + *cubeObj->getRigidBody()->m_torque = extTorque; + scene->getActiveCamera()->setFocalPoint(cubeObj->getRigidBody()->getPosition()); + scene->getActiveCamera()->setPosition(cubeObj->getRigidBody()->getPosition() + dx); + }); + + // Start viewer running, scene as paused + sceneManager->requestStatus(ThreadStatus::Paused); + viewer->start(); + } + + return 0; +} diff --git a/Examples/RigidBodyVirtualCoupling/RigidBodyVirtualCouplingExample.cpp b/Examples/RigidBodyVirtualCoupling/RigidBodyVirtualCouplingExample.cpp index ee7b4dbdd6b0c041a06dbb75009e51b438235827..ed6df35219da121c25c5dd32e838fb06fb7114e3 100644 --- a/Examples/RigidBodyVirtualCoupling/RigidBodyVirtualCouplingExample.cpp +++ b/Examples/RigidBodyVirtualCoupling/RigidBodyVirtualCouplingExample.cpp @@ -19,28 +19,29 @@ =========================================================================*/ -#include "imstkSimulationManager.h" -#include "imstkSceneManager.h" -#include "imstkSceneObject.h" -#include "imstkTetrahedralMesh.h" -#include "imstkSimulationManager.h" -#include "imstkVirtualCouplingCH.h" -#include "imstkHDAPIDeviceServer.h" -#include "imstkHDAPIDeviceClient.h" -#include "imstkSceneObjectController.h" -#include "imstkPlane.h" -#include "imstkSphere.h" -#include "imstkRigidObject.h" -#include "imstkRigidBodyModel.h" -#include "imstkMeshIO.h" +#include "imstkCamera.h" #include "imstkCube.h" +#include "imstkHapticDeviceClient.h" +#include "imstkHapticDeviceManager.h" #include "imstkIsometricMap.h" +#include "imstkKeyboardSceneControl.h" #include "imstkLight.h" -#include "imstkCamera.h" +#include "imstkLogger.h" +#include "imstkMeshIO.h" +#include "imstkMouseSceneControl.h" +#include "imstkNew.h" +#include "imstkPlane.h" +#include "imstkRenderMaterial.h" #include "imstkRigidBodyModel.h" -#include "imstkCollisionGraph.h" -#include "imstkDeviceTracker.h" +#include "imstkRigidObject.h" #include "imstkScene.h" +#include "imstkSceneManager.h" +#include "imstkSceneObjectController.h" +#include "imstkSphere.h" +#include "imstkSurfaceMesh.h" +#include "imstkTetrahedralMesh.h" +#include "imstkVisualModel.h" +#include "imstkVTKViewer.h" // global variables const std::string phantomOmni1Name = "Default Device"; @@ -48,226 +49,237 @@ const std::string phantomOmni1Name = "Default Device"; using namespace imstk; std::shared_ptr<imstk::RigidObject> -addMeshRigidObject(std::string& name, std::shared_ptr<Scene> scene, Vec3d pos) +makeMeshRigidObject(const std::string& name, const Vec3d& pos) { // create cube object - auto meshObj = std::make_shared<RigidObject>(name); + imstkNew<RigidObject> meshObj("name"); // Load a tetrahedral mesh - auto tetMesh = imstk::MeshIO::read(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg"); + auto tetMesh = MeshIO::read<TetrahedralMesh>(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg"); if (!tetMesh) { LOG(FATAL) << "Could not read mesh from file."; } // Extract the surface mesh - auto surfMesh = std::make_shared<SurfaceMesh>(); - auto volTetMesh = std::dynamic_pointer_cast<TetrahedralMesh>(tetMesh); - if (!volTetMesh) - { - LOG(FATAL) << "Dynamic pointer cast from PointSet to TetrahedralMesh failed!"; - } - volTetMesh->scale(15., Geometry::TransformType::ApplyToData); - volTetMesh->translate(pos, Geometry::TransformType::ApplyToData); - volTetMesh->extractSurfaceMesh(surfMesh, true); - - // add visual model - auto renderModel = std::make_shared<VisualModel>(surfMesh); - auto mat = std::make_shared<RenderMaterial>(); - mat->setDisplayMode(RenderMaterial::WireframeSurface); - mat->setLineWidth(2.); + imstkNew<SurfaceMesh> surfMesh; + tetMesh->scale(15.0, Geometry::TransformType::ApplyToData); + tetMesh->translate(pos, Geometry::TransformType::ApplyToData); + tetMesh->extractSurfaceMesh(surfMesh, true); + + // Add visual model + imstkNew<VisualModel> renderModel(surfMesh.get()); + imstkNew<RenderMaterial> mat; + mat->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface); + mat->setLineWidth(2.0); mat->setColor(Color::Green); renderModel->setRenderMaterial(mat); meshObj->addVisualModel(renderModel); // add dynamic model - auto rigidModel = std::make_shared<RigidBodyModel>(); - auto rigidProp = std::make_shared<RigidBodyConfig>(); - rigidProp->m_rigidBodyType = RigidBodyType::Kinematic; - rigidModel->configure(rigidProp); + imstkNew<RigidBodyModel> rigidModel; + imstkNew<RigidBodyConfig> rigidConfig; + rigidConfig->m_rigidBodyType = RigidBodyType::Kinematic; + rigidModel->configure(rigidConfig); rigidModel->setModelGeometry(surfMesh); meshObj->setPhysicsGeometry(surfMesh); meshObj->setDynamicalModel(rigidModel); - // add cube to scene - scene->addSceneObject(meshObj); return meshObj; } std::shared_ptr<imstk::RigidObject> -addCubeRigidObject(std::string& name, std::shared_ptr<Scene> scene, Vec3d pos, const bool isStatic = false) +makeCubeRigidObject(const std::string& name, const Vec3d& pos, const bool isStatic) { // create cube object - auto cubeObj = std::make_shared<RigidObject>(name); + imstkNew<RigidObject> cubeObj(name); // Create Cube object - auto cubeGeom = std::make_shared<Cube>(); - cubeGeom->setWidth(20.); - cubeGeom->translate(pos); + imstkNew<Cube> cubeGeom(pos, 20.0); // cube visual model - auto mesh = imstk::MeshIO::read(iMSTK_DATA_ROOT "/asianDragon/asianDragon.obj"); - auto SurfaceMesh = std::dynamic_pointer_cast<imstk::SurfaceMesh>(mesh); - SurfaceMesh->scale(5., Geometry::TransformType::ApplyToData); - auto renderModel = std::make_shared<VisualModel>(cubeGeom); - auto mat = std::make_shared<RenderMaterial>(); - mat->setDisplayMode(RenderMaterial::Surface); - mat->setLineWidth(2.); + auto surfMesh = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/asianDragon/asianDragon.obj"); + surfMesh->scale(5., Geometry::TransformType::ApplyToData); + imstkNew<VisualModel> renderModel(cubeGeom.get()); + imstkNew<RenderMaterial> mat; + mat->setDisplayMode(RenderMaterial::DisplayMode::Surface); + mat->setLineWidth(2.0); mat->setColor(Color::Orange); renderModel->setRenderMaterial(mat); cubeObj->addVisualModel(renderModel); - auto rigidMap = std::make_shared<IsometricMap>(); + imstkNew<IsometricMap> rigidMap; rigidMap->setMaster(cubeGeom); - rigidMap->setSlave(SurfaceMesh); + rigidMap->setSlave(surfMesh); // cube dynamic model - auto rigidModel = std::make_shared<RigidBodyModel>(); - auto rigidProp = std::make_shared<RigidBodyConfig>(); - rigidProp->m_rigidBodyType = RigidBodyType::Dynamic; - rigidModel->configure(rigidProp); + imstkNew<RigidBodyModel> rigidModel; + imstkNew<RigidBodyConfig> rigidConfig; + rigidConfig->m_rigidBodyType = RigidBodyType::Dynamic; + rigidModel->configure(rigidConfig); rigidModel->setModelGeometry(cubeGeom); cubeObj->setDynamicalModel(rigidModel); cubeObj->setPhysicsToVisualMap(rigidMap); - // add cube to scene - scene->addSceneObject(cubeObj); return cubeObj; } -void -addPlaneRigidObject(std::shared_ptr<Scene> scene) +std::shared_ptr<RigidObject> +makePlaneRigidObject(const double width) { // create plane object - auto planeObj = std::make_shared<RigidObject>("Plane"); + imstkNew<RigidObject> planeObj("Plane"); - auto planeGeom = std::make_shared<Plane>(); - planeGeom->setWidth(400.); + imstkNew<Plane> planeGeom; + planeGeom->setWidth(width); // visual model - auto renderModel2 = std::make_shared<VisualModel>(planeGeom); - renderModel2->setRenderMaterial(std::make_shared<RenderMaterial>()); - planeObj->addVisualModel(renderModel2); + imstkNew<VisualModel> renderModel(planeGeom.get()); + renderModel->setRenderMaterial(std::make_shared<RenderMaterial>()); + planeObj->addVisualModel(renderModel); // dynamic model - auto rigidModel2 = std::make_shared<RigidBodyModel>(); - auto rigidProp2 = std::make_shared<RigidBodyConfig>(); - rigidProp2->m_rigidBodyType = RigidBodyType::Static; - rigidModel2->configure(rigidProp2); - rigidModel2->setModelGeometry(planeGeom); - planeObj->setDynamicalModel(rigidModel2); - - scene->addSceneObject(planeObj); + imstkNew<RigidBodyModel> rigidModel; + imstkNew<RigidBodyConfig> rigidConfig; + rigidConfig->m_rigidBodyType = RigidBodyType::Static; + rigidModel->configure(rigidConfig); + rigidModel->setModelGeometry(planeGeom); + planeObj->setDynamicalModel(rigidModel); + + return planeObj; } -void -addSphereRigidObject(std::shared_ptr<Scene> scene, Vec3d t = Vec3d(0., 0., 0.)) +std::shared_ptr<RigidObject> +makeSphereRigidObject(const Vec3d& t) { // create cube object - auto sphereObj = std::make_shared<RigidObject>("Sphere"); + imstkNew<RigidObject> sphereObj("Sphere"); // Create Cube object - auto sphereGeom = std::make_shared<Sphere>(); - sphereGeom->setRadius(10.); + imstkNew<Sphere> sphereGeom; + sphereGeom->setRadius(10.0); sphereGeom->translate(t); // cube visual model - auto renderModel = std::make_shared<VisualModel>(sphereGeom); + imstkNew<VisualModel> renderModel(sphereGeom.get()); renderModel->setRenderMaterial(std::make_shared<RenderMaterial>()); sphereObj->addVisualModel(renderModel); // cube dynamic model - auto rigidModel3 = std::make_shared<RigidBodyModel>(); - auto rigidProp = std::make_shared<RigidBodyConfig>(); - rigidProp->m_rigidBodyType = RigidBodyType::Dynamic; - rigidModel3->configure(rigidProp); - rigidModel3->setModelGeometry(sphereGeom); - sphereObj->setDynamicalModel(rigidModel3); - - // add cube to scene - scene->addSceneObject(sphereObj); + imstkNew<RigidBodyModel> rigidModel; + imstkNew<RigidBodyConfig> rigidConfig; + rigidConfig->m_rigidBodyType = RigidBodyType::Dynamic; + rigidModel->configure(rigidConfig); + rigidModel->setModelGeometry(sphereGeom); + sphereObj->setDynamicalModel(rigidModel); + + return sphereObj; } int main() { - //simManager and Scene - auto simManager = std::make_shared<SimulationManager>(); - auto scene = simManager->createNewScene("Rigid Body Dynamics"); + // Setup logger (write to file and stdout) + Logger::startLogger(); - auto cubeObj = addCubeRigidObject(std::string("cube"), scene, Vec3d(0., 0., 0.)); + // Create Scene + imstkNew<Scene> scene("ControlRB"); - addPlaneRigidObject(scene); - //addSphereRigidObject(scene, Vec3d(0., 200, 0.)); - auto rigidObj = addMeshRigidObject(std::string("dragon"), scene, Vec3d(0., 30., 0.)); + std::shared_ptr<RigidObject> cubeObj = makeCubeRigidObject("cube", Vec3d(0.0, 0.0, 0.0), false); + scene->addSceneObject(cubeObj); - //------------------------------------------------------------- + std::shared_ptr<RigidObject> planeObj = makePlaneRigidObject(400.0); + scene->addSceneObject(planeObj); + + //makeSphereRigidObject(Vec3d(0.0, 200.0, 0..0)); - // Device clients - auto client = std::make_shared<HDAPIDeviceClient>(phantomOmni1Name); + std::shared_ptr<RigidObject> meshObj = makeMeshRigidObject("dragon", Vec3d(0.0, 30.0, 0.0)); + scene->addSceneObject(meshObj); + + //------------------------------------------------------------- // Device Server - auto server = std::make_shared<HDAPIDeviceServer>(); - server->addDeviceClient(client); - simManager->addModule(server); + imstkNew<HapticDeviceManager> server; + std::shared_ptr<HapticDeviceClient> client = server->makeDeviceClient(phantomOmni1Name); // Create a virtual coupling object - auto visualGeom = std::make_shared<Sphere>(); - visualGeom->setRadius(5.); - auto obj = std::make_shared<VisualObject>("VirtualCouplingObject"); - auto material = std::make_shared<RenderMaterial>(); - auto visualModel = std::make_shared<VisualModel>(visualGeom); + imstkNew<Sphere> visualGeom(Vec3d(0.0, 0.0, 0.0), 5.0); + imstkNew<VisualObject> obj("virtualCouplingObject"); + imstkNew<RenderMaterial> material; + imstkNew<VisualModel> visualModel(visualGeom.get()); visualModel->setRenderMaterial(material); obj->addVisualModel(visualModel); scene->addSceneObject(obj); // Device tracker - auto deviceTracker = std::make_shared<DeviceTracker>(client); - auto objController = std::make_shared<imstk::SceneObjectController>(obj, deviceTracker); - scene->addObjectController(objController); + imstkNew<SceneObjectController> controller(obj, client); + scene->addController(controller); //----------------------------------------------------------------- + std::shared_ptr<RigidBodyModel> rbdModel = cubeObj->getRigidBodyModel(); - auto rbModel = std::dynamic_pointer_cast<RigidBodyModel>(cubeObj->getDynamicalModel()); - - if (!rbModel) + if (!rbdModel.get()) { - addCubeRigidObject(std::string("cube"), scene, Vec3d(0., 40., 0.)); + std::shared_ptr<RigidObject> cubeObj2 = makeCubeRigidObject("cube", Vec3d(0.0, 40.0, 0.0), false); + scene->addSceneObject(cubeObj2); // throw error } - auto prevCubePos = rbModel->getModelGeometry()->getTranslation(); - - auto forceFunc = - [&](Module* module) - { - auto devPos = deviceTracker->getPosition(); - auto devQ = deviceTracker->getRotation(); - rbModel->getModelGeometry()->rotate(devQ); - auto cubeGeo = std::dynamic_pointer_cast<Cube>(cubeObj->getPhysicsGeometry()); - auto cubePos = rbModel->getModelGeometry()->getTranslation(); - auto cubeVelocity = (cubePos - prevCubePos) / 2; - auto damp = -1000000 * cubeVelocity; - auto force = -1000 * (cubePos - devPos) + damp; - rbModel->addForce(force, Vec3d(0., 0., 0.)); - prevCubePos = cubePos; - }; - simManager->getSceneManager(scene)->setPreUpdateCallback(forceFunc); - - //------------------------------------------------------------------- // Set Camera configuration - auto cam = scene->getCamera(); - cam->setPosition(Vec3d(300, 300, 300)); + scene->getActiveCamera()->setPosition(Vec3d(300.0, 300.0, 300.0)); // Light - auto light = std::make_shared<DirectionalLight>("light"); - light->setIntensity(1); + imstkNew<DirectionalLight> light("light"); + light->setIntensity(1.0); scene->addLight(light); // Run - simManager->setActiveScene(scene); - simManager->start(SimulationStatus::Paused); + //Run the simulation + { + // Setup a viewer to render in its own thread + imstkNew<VTKViewer> viewer("Viewer 1"); + viewer->setActiveScene(scene); + + // Setup a scene manager to advance the scene in its own thread + imstkNew<SceneManager> sceneManager("Scene Manager 1"); + sceneManager->setActiveScene(scene); + viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer + + viewer->addChildThread(server); + + // Add mouse and keyboard controls to the viewer + { + imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice()); + mouseControl->setSceneManager(sceneManager); + viewer->addControl(mouseControl); + + imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice()); + keyControl->setSceneManager(sceneManager); + keyControl->setViewer(viewer); + viewer->addControl(keyControl); + } + + Vec3d prevCubePos = rbdModel->getModelGeometry()->getTranslation(); + connect<Event>(sceneManager, EventType::PostUpdate, + [&](Event*) + { + const auto devPos = controller->getPosition(); + const auto devQ = controller->getRotation(); + rbdModel->getModelGeometry()->rotate(devQ); + auto cubeGeo = std::dynamic_pointer_cast<Cube>(cubeObj->getPhysicsGeometry()); + const Vec3d cubePos = rbdModel->getModelGeometry()->getTranslation(); + const Vec3d cubeVelocity = (cubePos - prevCubePos) / 2.0; + const Vec3d damp = -1000000 * cubeVelocity; + const Vec3d force = -1000 * (cubePos - devPos) + damp; + rbdModel->addForce(force, Vec3d(0.0, 0.0, 0.0)); + prevCubePos = cubePos; + }); + + // Start viewer running, scene as paused + sceneManager->requestStatus(ThreadStatus::Paused); + viewer->start(); + } return 0; } \ No newline at end of file diff --git a/Examples/SPH-FEM-PBD/CMakeLists.txt b/Examples/SPH-FEM-PBD/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..ba29ce91b42b06e1fba32118fab4cb9ba38ccefc --- /dev/null +++ b/Examples/SPH-FEM-PBD/CMakeLists.txt @@ -0,0 +1,34 @@ +########################################################################### +# +# Copyright (c) Kitware, Inc. +# +# 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. +# +########################################################################### + +project(Example-SPH-FEM-PBD) + +#----------------------------------------------------------------------------- +# Create executable +#----------------------------------------------------------------------------- +imstk_add_executable(${PROJECT_NAME} sphFemPbdExample.cpp) + +#----------------------------------------------------------------------------- +# Add the target to Examples folder +#----------------------------------------------------------------------------- +SET_TARGET_PROPERTIES (${PROJECT_NAME} PROPERTIES FOLDER Examples) + +#----------------------------------------------------------------------------- +# Link libraries to executable +#----------------------------------------------------------------------------- +target_link_libraries(${PROJECT_NAME} SimulationManager) diff --git a/Examples/SPH-FEM-PBD/sphFemPbdExample.cpp b/Examples/SPH-FEM-PBD/sphFemPbdExample.cpp new file mode 100644 index 0000000000000000000000000000000000000000..22d490fe57830fa3e1cc675f4e825653bb2f6f8b --- /dev/null +++ b/Examples/SPH-FEM-PBD/sphFemPbdExample.cpp @@ -0,0 +1,311 @@ +/*========================================================================= + + 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 "imstkBackwardEuler.h" +#include "imstkCamera.h" +#include "imstkFeDeformableObject.h" +#include "imstkFEMDeformableBodyModel.h" +#include "imstkImageData.h" +#include "imstkKeyboardSceneControl.h" +#include "imstkLight.h" +#include "imstkMeshIO.h" +#include "imstkMouseSceneControl.h" +#include "imstkNew.h" +#include "imstkOneToOneMap.h" +#include "imstkPbdConstraint.h" +#include "imstkPbdModel.h" +#include "imstkPbdObject.h" +#include "imstkRenderMaterial.h" +#include "imstkScene.h" +#include "imstkSceneManager.h" +#include "imstkSPHModel.h" +#include "imstkSPHObject.h" +#include "imstkSurfaceMesh.h" +#include "imstkTaskGraphVizWriter.h" +#include "imstkTetrahedralMesh.h" +#include "imstkTetraTriangleMap.h" +#include "imstkViewer.h" +#include "imstkVisualModel.h" +#include "imstkVTKViewer.h" + +using namespace imstk; + +/// +/// \brief Generate a box-shape fluid object +/// \param radius of SPH particles/used for spacing +/// \param center of the SPH fluid box +/// \param size of the SPH fluid box +/// +std::shared_ptr<StdVectorOfVec3d> +generateBoxShapeFluid(const double particleRadius, const Vec3d& boxCenter, const Vec3d& boxSize) +{ + double bounds[6] = + { + boxCenter.x() - boxSize.x() * 0.5, + boxCenter.x() + boxSize.x() * 0.5, + boxCenter.y() - boxSize.y() * 0.5, + boxCenter.y() + boxSize.y() * 0.5, + boxCenter.z() - boxSize.z() * 0.5, + boxCenter.z() + boxSize.z() * 0.5 + }; + + const double spacing = 2.0 * particleRadius; + const Vec3i dim = { + static_cast<int>(boxSize.x() / spacing), + static_cast<int>(boxSize.y() / spacing), + static_cast<int>(boxSize.z() / spacing) }; + + imstkNew<StdVectorOfVec3d> particles; + particles->reserve(dim[0] * dim[1] * dim[2]); + + for (double z = bounds[4]; z < bounds[5]; z += spacing) + { + for (double y = bounds[2]; y < bounds[3]; y += spacing) + { + for (double x = bounds[0]; x < bounds[1]; x += spacing) + { + particles->push_back(Vec3d(x, y, z)); + } + } + } + + return particles; +} + +/// +/// \brief Generate an SPH Box Object +/// \param name of the object +/// \param radius of SPH particles +/// \param shift/position of the fluid box +/// \parma dimensions of the fluid box +/// +std::shared_ptr<SPHObject> +makeSPHBoxObject(const std::string& name, const double particleRadius, const Vec3d& boxShift, const Vec3d& boxSize) +{ + // Create the sph object + imstkNew<SPHObject> fluidObj(name); + + // Setup the Geometry + std::shared_ptr<StdVectorOfVec3d> particles = generateBoxShapeFluid(particleRadius, boxShift, boxSize); + LOG(INFO) << "Number of particles: " << particles->size(); + imstkNew<PointSet> fluidGeometry; + fluidGeometry->initialize(*particles); + + // Setup the Parameters + imstkNew<SPHModelConfig> sphParams(particleRadius); + sphParams->m_bNormalizeDensity = true; + sphParams->m_kernelOverParticleRadiusRatio = 6.0; + sphParams->m_viscosityCoeff = 0.5; + sphParams->m_surfaceTensionStiffness = 5.0; + + // Setup the Model + imstkNew<SPHModel> sphModel; + sphModel->setModelGeometry(fluidGeometry); + sphModel->configure(sphParams); + sphModel->setTimeStepSizeType(TimeSteppingType::RealTime); + + // Setup the VisualModel + imstkNew<VisualModel> fluidVisualModel(fluidGeometry.get()); + imstkNew<RenderMaterial> fluidMaterial; + fluidMaterial->setDisplayMode(RenderMaterial::DisplayMode::Fluid); + fluidMaterial->setVertexColor(Color::Orange); + fluidMaterial->setPointSize(static_cast<double>(particleRadius)); + fluidVisualModel->setRenderMaterial(fluidMaterial); + + // Setup the Object + fluidObj->addVisualModel(fluidVisualModel); + fluidObj->setCollidingGeometry(fluidGeometry); + fluidObj->setDynamicalModel(sphModel); + fluidObj->setPhysicsGeometry(fluidGeometry); + + return fluidObj; +} + +/// +/// \brief Generate a Deformable object simulated with FEM +/// \param name of the object +/// \param position of the object +/// +static std::shared_ptr<FeDeformableObject> +makeFEDragonObject(const std::string& name, const Vec3d& position) +{ + // Create the sph object + imstkNew<FeDeformableObject> object(name); + + // Setup the Geometry + auto tetMesh = MeshIO::read<TetrahedralMesh>(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg"); + tetMesh->translate(position, Geometry::TransformType::ApplyToData); + imstkNew<SurfaceMesh> surfMesh; + tetMesh->extractSurfaceMesh(surfMesh, true); + + // Setup the Parameters + imstkNew<FEMModelConfig> config; + config->m_fixedNodeIds = { 50, 126, 177 }; + + // Setup the Model + imstkNew<FEMDeformableBodyModel> dynaModel; + dynaModel->configure(config); + dynaModel->setTimeStepSizeType(TimeSteppingType::Fixed); + dynaModel->setModelGeometry(tetMesh); + imstkNew<BackwardEuler> timeIntegrator(0.01); + dynaModel->setTimeIntegrator(timeIntegrator); + + // Setup the VisualModel + imstkNew<VisualModel> surfMeshModel(surfMesh.get()); + imstkNew<RenderMaterial> material; + material->setDisplayMode(RenderMaterial::DisplayMode::Surface); + surfMeshModel->setRenderMaterial(material); + + // Setup the Object + object->addVisualModel(surfMeshModel); + object->setPhysicsGeometry(tetMesh); + object->setPhysicsToVisualMap(std::make_shared<OneToOneMap>(tetMesh, surfMesh)); + object->setDynamicalModel(dynaModel); + + return object; +} + +/// +/// \brief Generate a Deformable object simulated with PBD +/// \param name of the object +/// \param position of the object +/// +static std::shared_ptr<PbdObject> +makePBDDragonObject(const std::string& name, const Vec3d& position) +{ + // Create the pbd object + imstkNew<PbdObject> pbdObj(name); + + // Setup the Geometry (read dragon mesh) + auto highResSurfMesh = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/asianDragon/asianDragon.obj"); + auto coarseTetMesh = MeshIO::read<TetrahedralMesh>(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg"); + highResSurfMesh->translate(position, Geometry::TransformType::ApplyToData); + coarseTetMesh->translate(position, Geometry::TransformType::ApplyToData); + imstkNew<SurfaceMesh> coarseSurfMesh; + coarseTetMesh->extractSurfaceMesh(coarseSurfMesh, true); + + // Setup the Parameters + imstkNew<PBDModelConfig> pbdParams; + pbdParams->m_femParams->m_YoungModulus = 1000.0; + pbdParams->m_femParams->m_PoissonRatio = 0.3; + pbdParams->m_fixedNodeIds = { 50, 126, 177 }; + pbdParams->enableFEMConstraint(PbdConstraint::Type::FEMTet, PbdFEMConstraint::MaterialType::StVK); + pbdParams->m_uniformMassValue = 1.0; + pbdParams->m_gravity = Vec3d(0, -9.8, 0); + pbdParams->m_defaultDt = 0.01; + pbdParams->m_iterations = 10; + pbdParams->collisionParams->m_proximity = 0.3; + pbdParams->collisionParams->m_stiffness = 0.1; + + // Setup the Model + imstkNew<PbdModel> model; + model->setModelGeometry(coarseTetMesh); + model->configure(pbdParams); + + // Setup the VisualModel + imstkNew<RenderMaterial> material; + material->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface); + imstkNew<VisualModel> surfMeshModel(highResSurfMesh); + surfMeshModel->setRenderMaterial(material); + + // Setup the Object + pbdObj->addVisualModel(surfMeshModel); + pbdObj->setCollidingGeometry(coarseSurfMesh); + pbdObj->setPhysicsGeometry(coarseTetMesh); + pbdObj->setPhysicsToCollidingMap(std::make_shared<OneToOneMap>(coarseTetMesh, coarseSurfMesh)); + pbdObj->setPhysicsToVisualMap(std::make_shared<TetraTriangleMap>(coarseTetMesh, highResSurfMesh)); + pbdObj->setDynamicalModel(model); + + return pbdObj; +} + +/// +/// \brief This example demonstrates 3 different models running at the same time +/// +int +main() +{ + // Setup logger (write to file and stdout) + Logger::startLogger(); + + imstkNew<Scene> scene("SPH-FEM-PBD"); + + // Setup the scene + { + scene->getConfig()->taskTimingEnabled = true; + scene->getActiveCamera()->setPosition(0.0, 2.0, 25.0); + + // Deformable Pbd Dragon + std::shared_ptr<PbdObject> pbdDragon = makePBDDragonObject("PBDDragon", Vec3d(-5.0, 0.0, 0.0)); + scene->addSceneObject(pbdDragon); + + // Deformable FEM dragon + std::shared_ptr<FeDeformableObject> feDragon = makeFEDragonObject("FEDragon", Vec3d(0.0, 0.0, 0.0)); + scene->addSceneObject(feDragon); + + // SPH fluid box overtop the dragon + std::shared_ptr<SPHObject> sphFluidBox = makeSPHBoxObject("Box", 0.1, Vec3d(5.0, 7.0, 0.0), Vec3d(3.0, 7.0, 3.0)); + scene->addSceneObject(sphFluidBox); + + // Light + imstkNew<DirectionalLight> light("light"); + light->setDirection(0.0, -1.0, -1.0); + light->setIntensity(1); + scene->addLight(light); + } + + // Run the simulation + { + // Setup a viewer to render in its own thread + imstkNew<VTKViewer> viewer("Viewer"); + viewer->setActiveScene(scene); + viewer->setBackgroundColors(Vec3d(0.3285, 0.3285, 0.6525), Vec3d(0.13836, 0.13836, 0.2748), true); + + // Setup a scene manager to advance the scene in its own thread + imstkNew<SceneManager> sceneManager("Scene Manager"); + sceneManager->setActiveScene(scene); + viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer + + // Add mouse and keyboard controls to the viewer + { + imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice()); + mouseControl->setSceneManager(sceneManager); + viewer->addControl(mouseControl); + + imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice()); + keyControl->setSceneManager(sceneManager); + keyControl->setViewer(viewer); + viewer->addControl(keyControl); + } + + // Start viewer running, scene as paused + sceneManager->requestStatus(ThreadStatus::Paused); + viewer->start(); + } + + imstkNew<TaskGraphVizWriter> writer; + writer->setFileName("sphFemPbdInteractionTaskGraph.svg"); + writer->setHighlightCriticalPath(true); + writer->setInput(scene->getTaskGraph()); + writer->write(); + + return 0; +} diff --git a/Examples/SPHFluid/Fluid.hpp b/Examples/SPHFluid/Fluid.hpp index ba3f7f7474367c3317df66bee530ace0474bc81f..54f5098971fef0f68c2e6f618eba83d085597a1d 100644 --- a/Examples/SPHFluid/Fluid.hpp +++ b/Examples/SPHFluid/Fluid.hpp @@ -19,11 +19,12 @@ =========================================================================*/ -#include "imstkSimulationManager.h" -#include "imstkSPHObject.h" -#include "imstkSPHModel.h" #include "imstkPointSet.h" +#include "imstkRenderMaterial.h" #include "imstkScene.h" +#include "imstkSPHObject.h" +#include "imstkSPHModel.h" +#include "imstkVisualModel.h" using namespace imstk; @@ -157,7 +158,7 @@ initializeNonZeroVelocities(const size_t numParticles) } std::shared_ptr<SPHObject> -generateFluid(const std::shared_ptr<Scene>& scene, const double particleRadius) +generateFluid(const double particleRadius) { StdVectorOfVec3d particles; StdVectorOfVec3d initialVelocities; @@ -186,26 +187,33 @@ generateFluid(const std::shared_ptr<Scene>& scene, const double particleRadius) LOG(INFO) << "Number of particles: " << particles.size(); // Create a geometry object - auto fluidGeometry = std::make_shared<PointSet>(); - fluidGeometry->initialize(particles); + imstkNew<PointSet> geometry; + geometry->initialize(particles); // Create a fluids object - auto fluidObj = std::make_shared<SPHObject>("Sphere"); + imstkNew<SPHObject> fluidObj("Sphere"); // Create a visual model - auto fluidVisualModel = std::make_shared<VisualModel>(fluidGeometry); - auto fluidMaterial = std::make_shared<RenderMaterial>(); - fluidMaterial->setDisplayMode(RenderMaterial::DisplayMode::Points); - fluidMaterial->setVertexColor(Color::Orange); - fluidMaterial->setPointSize(10.); - fluidVisualModel->setRenderMaterial(fluidMaterial); + imstkNew<VisualModel> visualModel(geometry.get()); + imstkNew<RenderMaterial> material; + material->setDisplayMode(RenderMaterial::DisplayMode::Fluid); + material->setVertexColor(Color::Orange); + if (material->getDisplayMode() == RenderMaterial::DisplayMode::Fluid) + { + material->setPointSize(0.1); + } + else + { + material->setPointSize(15.0); + } + visualModel->setRenderMaterial(material); // Create a physics model - auto sphModel = std::make_shared<SPHModel>(); - sphModel->setModelGeometry(fluidGeometry); + imstkNew<SPHModel> sphModel; + sphModel->setModelGeometry(geometry); - // configure model - auto sphParams = std::make_shared<SPHModelConfig>(particleRadius); + // Configure model + imstkNew<SPHModelConfig> sphParams(particleRadius); sphParams->m_bNormalizeDensity = true; if (SCENE_ID == 2) // highly viscous fluid { @@ -223,11 +231,10 @@ generateFluid(const std::shared_ptr<Scene>& scene, const double particleRadius) sphModel->setTimeStepSizeType(TimeSteppingType::RealTime); // Add the component models - fluidObj->addVisualModel(fluidVisualModel); - fluidObj->setCollidingGeometry(fluidGeometry); + fluidObj->addVisualModel(visualModel); + fluidObj->setCollidingGeometry(geometry); fluidObj->setDynamicalModel(sphModel); - fluidObj->setPhysicsGeometry(fluidGeometry); // TODO: Look into API duplication and resulting conflicts - scene->addSceneObject(fluidObj); + fluidObj->setPhysicsGeometry(geometry); return fluidObj; } diff --git a/Examples/SPHFluid/SPHFluidExample.hpp b/Examples/SPHFluid/SPHFluidExample.hpp index 9447fcb89f58f5c25f23f55f254e0ff54d68dcd5..77a3c2745765e0873725813e22132694be8337e9 100644 --- a/Examples/SPHFluid/SPHFluidExample.hpp +++ b/Examples/SPHFluid/SPHFluidExample.hpp @@ -19,20 +19,18 @@ =========================================================================*/ -#include <string> - -#include "imstkSimulationManager.h" +#include "imstkCamera.h" +#include "imstkCollisionDetection.h" +#include "imstkCollisionGraph.h" +#include "imstkKeyboardSceneControl.h" #include "imstkLight.h" +#include "imstkMouseSceneControl.h" +#include "imstkNew.h" +#include "imstkObjectInteractionFactory.h" +#include "imstkSceneManager.h" #include "imstkSPHObject.h" -#include "imstkAPIUtilities.h" -#include "imstkPlane.h" -#include "imstkSphere.h" #include "imstkVTKTextStatusManager.h" -#include "imstkCollisionGraph.h" -#include "imstkSceneManager.h" -#include "imstkCamera.h" -#include "imstkObjectInteractionFactory.h" -#include "imstkCollisionDetection.h" +#include "imstkVTKViewer.h" #include "Fluid.hpp" #include "Solid.hpp" @@ -46,22 +44,16 @@ using namespace imstk; int main(int argc, char* argv[]) { - // SimulationManager must be created first - auto simManager = std::make_shared<SimulationManager>(); + // Setup logger (write to file and stdout) + Logger::startLogger(); - int threads = -1; double particleRadius = 0.1; // Parse command line arguments for (int i = 1; i < argc; ++i) { auto param = std::string(argv[i]); - if (param.find("threads") == 0 - && param.find_first_of("=") != std::string::npos) - { - threads = std::stoi(param.substr(param.find_first_of("=") + 1)); - } - else if (param.find("radius") == 0 + if (param.find("radius") == 0 && param.find_first_of("=") != std::string::npos) { particleRadius = std::stod(param.substr(param.find_first_of("=") + 1)); @@ -79,29 +71,17 @@ main(int argc, char* argv[]) particleRadius = 0.08; } - // Set thread pool size (nthreads <= 0 means using all logical cores) - simManager->setThreadPoolSize(threads); - - auto scene = simManager->createNewScene("SPH Fluid"); - - // Create the viewer - std::shared_ptr<VTKViewer> viewer = std::make_shared<VTKViewer>(simManager.get(), false); - viewer->setWindowTitle("SPH Fluid"); - viewer->getVtkRenderWindow()->SetSize(1920, 1080); - auto statusManager = viewer->getTextStatusManager(); - statusManager->setStatusFontSize(VTKTextStatusManager::Custom, 30); - statusManager->setStatusFontColor(VTKTextStatusManager::Custom, Color::Red); - simManager->setViewer(viewer); + imstkNew<Scene> scene("SPH Fluid"); // Generate fluid and solid objects - auto fluidObj = generateFluid(scene, particleRadius); - auto solids = generateSolids(scene); + std::shared_ptr<SPHObject> fluidObj = generateFluid(particleRadius); + std::vector<std::shared_ptr<CollidingObject>> solids = generateSolids(); - simManager->getSceneManager(scene)->setPostUpdateCallback([&](Module*) { - statusManager->setCustomStatus("Number of particles: " + - std::to_string(fluidObj->getSPHModel()->getState().getNumParticles()) + - "\nNumber of solids: " + std::to_string(solids.size())); - }); + scene->addSceneObject(fluidObj); + for (size_t i = 0; i < solids.size(); i++) + { + scene->addSceneObject(solids[i]); + } // Collision between fluid and solid objects std::shared_ptr<CollisionGraph> collisionGraph = scene->getCollisionGraph(); @@ -124,16 +104,53 @@ main(int argc, char* argv[]) } // configure camera - scene->getCamera()->setPosition(0, 10.0, 15.0); + scene->getActiveCamera()->setPosition(-0.475, 8.116, -6.728); // configure light (white) - auto whiteLight = std::make_shared<DirectionalLight>("whiteLight"); - whiteLight->setFocalPoint(Vec3d(5, -8, -5)); + imstkNew<DirectionalLight> whiteLight("whiteLight"); + whiteLight->setFocalPoint(Vec3d(5.0, -8.0, -5.0)); whiteLight->setIntensity(1.5); scene->addLight(whiteLight); - simManager->setActiveScene(scene); - simManager->start(SimulationStatus::Paused); + // Run the simulation + { + // Setup a viewer to render in its own thread + imstkNew<VTKViewer> viewer("Viewer"); + viewer->setActiveScene(scene); + viewer->setWindowTitle("SPH Fluid"); + viewer->setSize(1920, 1080); + auto statusManager = viewer->getTextStatusManager(); + statusManager->setStatusFontSize(VTKTextStatusManager::StatusType::Custom, 30); + statusManager->setStatusFontColor(VTKTextStatusManager::StatusType::Custom, Color::Red); + connect<Event>(viewer, EventType::PostUpdate, + [&](Event*) + { + statusManager->setCustomStatus("Number of particles: " + + std::to_string(fluidObj->getSPHModel()->getState().getNumParticles()) + + "\nNumber of solids: " + std::to_string(solids.size())); + }); + + // Setup a scene manager to advance the scene in its own thread + imstkNew<SceneManager> sceneManager("Scene Manager"); + sceneManager->setActiveScene(scene); + viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer + + // Add mouse and keyboard controls to the viewer + { + imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice()); + mouseControl->setSceneManager(sceneManager); + viewer->addControl(mouseControl); + + imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice()); + keyControl->setSceneManager(sceneManager); + keyControl->setViewer(viewer); + viewer->addControl(keyControl); + } + + // Start viewer running, scene as paused + sceneManager->requestStatus(ThreadStatus::Paused); + viewer->start(); + } return 0; } diff --git a/Examples/SPHFluid/Solid.hpp b/Examples/SPHFluid/Solid.hpp index 8e9ce4ba917baf0b9009b436e06a0b6ee6842f12..5cb6cd919b7889d20910c80cbcbc9d9334af2357 100644 --- a/Examples/SPHFluid/Solid.hpp +++ b/Examples/SPHFluid/Solid.hpp @@ -27,7 +27,9 @@ //#include "imstkGeometryUtilities.h" #include "imstkSimulationManager.h" + #include "imstkPlane.h" +#include "imstkRenderMaterial.h" #include "imstkSphere.h" using namespace imstk; @@ -35,58 +37,55 @@ using namespace imstk; /// /// \brief Generate two planes and a solid sphere /// -std::vector<std::shared_ptr<CollidingObject>> generateSolidsScene1(const std::shared_ptr<Scene>& scene) +std::vector<std::shared_ptr<CollidingObject>> generateSolidsScene1() { std::vector<std::shared_ptr<CollidingObject>> solids; { - auto geometry = std::make_shared<Plane>(); - geometry->setWidth(40); - geometry->setPosition(0, -6, 0); - geometry->setNormal(Vec3d(0, 1, -0.5)); + imstkNew<Plane> geometry; + geometry->setWidth(40.0); + geometry->setPosition(0.0, -6.0, 0.0); + geometry->setNormal(Vec3d(0.0, 1.0, -0.5)); - auto visualModel = std::make_shared<VisualModel>(geometry); - auto material = std::make_shared<RenderMaterial>(); + imstkNew<VisualModel> visualModel(geometry.get()); + imstkNew<RenderMaterial> material; material->setColor(Color::DarkGray); visualModel->setRenderMaterial(material); - auto obj = std::make_shared<CollidingObject>("Floor"); + imstkNew<CollidingObject> obj("Floor"); obj->addVisualModel(visualModel); obj->setCollidingGeometry(geometry); - scene->addSceneObject(obj); solids.push_back(obj); } { - auto geometry = std::make_shared<Plane>(); - geometry->setWidth(40); - geometry->setPosition(0, -6, 0); - geometry->setNormal(Vec3d(0, 1, 1)); + imstkNew<Plane> geometry; + geometry->setWidth(40.0); + geometry->setPosition(0.0, -6.0, 0.0); + geometry->setNormal(Vec3d(0.0, 1.0, 1.0)); - auto visualModel = std::make_shared<VisualModel>(geometry); - auto material = std::make_shared<RenderMaterial>(); + imstkNew<VisualModel> visualModel(geometry.get()); + imstkNew<RenderMaterial> material; material->setColor(Color::LightGray); visualModel->setRenderMaterial(material); - auto obj = std::make_shared<CollidingObject>("Back Plane"); + imstkNew<CollidingObject> obj("Back Plane"); obj->addVisualModel(visualModel); obj->setCollidingGeometry(geometry); - scene->addSceneObject(obj); solids.push_back(obj); } { - auto geometry = std::make_shared<Sphere>(); - geometry->setRadius(2); - geometry->setPosition(0, -6, 0); + imstkNew<Sphere> geometry; + geometry->setRadius(2.0); + geometry->setPosition(0.0, -6.0, 0.0); - auto visualModel = std::make_shared<VisualModel>(geometry); - auto material = std::make_shared<RenderMaterial>(); + imstkNew<VisualModel> visualModel(geometry.get()); + imstkNew<RenderMaterial> material; material->setColor(Color::Red); visualModel->setRenderMaterial(material); - auto obj = std::make_shared<CollidingObject>("Sphere on Floor"); + imstkNew<CollidingObject> obj("Sphere on Floor"); obj->addVisualModel(visualModel); obj->setCollidingGeometry(geometry); - scene->addSceneObject(obj); solids.push_back(obj); } @@ -96,42 +95,40 @@ std::vector<std::shared_ptr<CollidingObject>> generateSolidsScene1(const std::sh /// /// \brief Generate two planes /// -std::vector<std::shared_ptr<CollidingObject>> generateSolidsScene2(const std::shared_ptr<Scene>& scene) +std::vector<std::shared_ptr<CollidingObject>> generateSolidsScene2() { std::vector<std::shared_ptr<CollidingObject>> solids; { - auto geometry = std::make_shared<Plane>(); - geometry->setWidth(40); - geometry->setPosition(0, -6, 0); - geometry->setNormal(Vec3d(0, 1, -0.5)); + imstkNew<Plane> geometry; + geometry->setWidth(40.0); + geometry->setPosition(0.0, -6.0, 0.0); + geometry->setNormal(Vec3d(0.0, 1.0, -0.5)); - auto visualModel = std::make_shared<VisualModel>(geometry); - auto material = std::make_shared<RenderMaterial>(); + imstkNew<VisualModel> visualModel(geometry.get()); + imstkNew<RenderMaterial> material; material->setColor(Color::DarkGray); visualModel->setRenderMaterial(material); - auto obj = std::make_shared<CollidingObject>("Floor"); + imstkNew<CollidingObject> obj("Floor"); obj->addVisualModel(visualModel); obj->setCollidingGeometry(geometry); - scene->addSceneObject(obj); solids.push_back(obj); } { - auto geometry = std::make_shared<Plane>(); - geometry->setWidth(40); - geometry->setPosition(0, -6, 0); - geometry->setNormal(Vec3d(0, 1, 1)); + imstkNew<Plane> geometry; + geometry->setWidth(40.0); + geometry->setPosition(0.0, -6.0, 0.0); + geometry->setNormal(Vec3d(0.0, 1.0, 1.0)); - auto visualModel = std::make_shared<VisualModel>(geometry); - auto material = std::make_shared<RenderMaterial>(); + imstkNew<VisualModel> visualModel(geometry.get()); + imstkNew<RenderMaterial> material; material->setColor(Color::LightGray); visualModel->setRenderMaterial(material); - auto obj = std::make_shared<CollidingObject>("Back Plane"); + imstkNew<CollidingObject> obj("Back Plane"); obj->addVisualModel(visualModel); obj->setCollidingGeometry(geometry); - scene->addSceneObject(obj); solids.push_back(obj); } @@ -141,93 +138,83 @@ std::vector<std::shared_ptr<CollidingObject>> generateSolidsScene2(const std::sh /// /// \brief Generate an open box by 5 planes: 1 floor and 4 walls /// -std::vector<std::shared_ptr<CollidingObject>> generateSolidsScene3(const std::shared_ptr<Scene>& scene) +std::vector<std::shared_ptr<CollidingObject>> generateSolidsScene3() { std::vector<std::shared_ptr<CollidingObject>> solids; + imstkNew<RenderMaterial> lightGrayMat; + lightGrayMat->setColor(Color::LightGray); + { - auto geometry = std::make_shared<Plane>(); - geometry->setWidth(14); - geometry->setPosition(0, -6, 0); - geometry->setNormal(Vec3d(0, 1, 0)); + imstkNew<Plane> geometry; + geometry->setWidth(14.0); + geometry->setPosition(0.0, -6.0, 0.0); + geometry->setNormal(Vec3d(0.0, 1.0, 0.0)); - auto visualModel = std::make_shared<VisualModel>(geometry); - auto material = std::make_shared<RenderMaterial>(); + imstkNew<VisualModel> visualModel(geometry.get()); + imstkNew<RenderMaterial> material; material->setColor(Color(0.2, 0.2, 0.2, 1.0)); visualModel->setRenderMaterial(material); - auto obj = std::make_shared<CollidingObject>("Floor"); + imstkNew<CollidingObject> obj("Floor"); obj->addVisualModel(visualModel); obj->setCollidingGeometry(geometry); - scene->addSceneObject(obj); solids.push_back(obj); } { - auto geometry = std::make_shared<Plane>(); - geometry->setWidth(14); - geometry->setPosition(0, 0, -7); - geometry->setNormal(Vec3d(0, 0, 1)); + imstkNew<Plane> geometry; + geometry->setWidth(14.0); + geometry->setPosition(0.0, 0.0, -7.0); + geometry->setNormal(Vec3d(0.0, 0.0, 1.0)); - auto visualModel = std::make_shared<VisualModel>(geometry); - auto material = std::make_shared<RenderMaterial>(); - material->setColor(Color::LightGray); - visualModel->setRenderMaterial(material); + imstkNew<VisualModel> visualModel(geometry.get()); + visualModel->setRenderMaterial(lightGrayMat); - auto obj = std::make_shared<CollidingObject>("Back Wall"); + imstkNew<CollidingObject> obj("Back Wall"); obj->addVisualModel(visualModel); obj->setCollidingGeometry(geometry); - scene->addSceneObject(obj); solids.push_back(obj); } { - auto geometry = std::make_shared<Plane>(); - geometry->setWidth(14); - geometry->setPosition(0, 0, 7); - geometry->setNormal(Vec3d(0, 0, -1)); + imstkNew<Plane> geometry; + geometry->setWidth(14.0); + geometry->setPosition(0.0, 0.0, 7.0); + geometry->setNormal(Vec3d(0.0, 0.0, -1.0)); - auto visualModel = std::make_shared<VisualModel>(geometry); - auto material = std::make_shared<RenderMaterial>(); - material->setColor(Color::LightGray); - visualModel->setRenderMaterial(material); + imstkNew<VisualModel> visualModel(geometry.get()); + visualModel->setRenderMaterial(lightGrayMat); - auto obj = std::make_shared<CollidingObject>("Front Wall"); + imstkNew<CollidingObject> obj("Front Wall"); obj->addVisualModel(visualModel); obj->setCollidingGeometry(geometry); - scene->addSceneObject(obj); solids.push_back(obj); } { - auto geometry = std::make_shared<Plane>(); - geometry->setWidth(14); - geometry->setPosition(7, 0, 0); - geometry->setNormal(Vec3d(-1, 0, 0)); + imstkNew<Plane> geometry; + geometry->setWidth(14.0); + geometry->setPosition(7.0, 0.0, 0.0); + geometry->setNormal(Vec3d(-1.0, 0.0, 0.0)); - auto visualModel = std::make_shared<VisualModel>(geometry); - auto material = std::make_shared<RenderMaterial>(); - material->setColor(Color::LightGray); - visualModel->setRenderMaterial(material); + imstkNew<VisualModel> visualModel(geometry.get()); + visualModel->setRenderMaterial(lightGrayMat); - auto obj = std::make_shared<CollidingObject>("Left Wall"); + imstkNew<CollidingObject> obj("Left Wall"); obj->addVisualModel(visualModel); obj->setCollidingGeometry(geometry); - scene->addSceneObject(obj); solids.push_back(obj); } { - auto geometry = std::make_shared<Plane>(); - geometry->setWidth(14); - geometry->setPosition(-7, 0, 0); - geometry->setNormal(Vec3d(1, 0, 0)); + imstkNew<Plane> geometry; + geometry->setWidth(14.0); + geometry->setPosition(-7.0, 0.0, 0.0); + geometry->setNormal(Vec3d(1.0, 0.0, 0.0)); - auto visualModel = std::make_shared<VisualModel>(geometry); - auto material = std::make_shared<RenderMaterial>(); - material->setColor(Color::LightGray); - visualModel->setRenderMaterial(material); + imstkNew<VisualModel> visualModel(geometry.get()); + visualModel->setRenderMaterial(lightGrayMat); - auto obj = std::make_shared<CollidingObject>("Right Wall"); + imstkNew<CollidingObject> obj("Right Wall"); obj->addVisualModel(visualModel); obj->setCollidingGeometry(geometry); - scene->addSceneObject(obj); solids.push_back(obj); } @@ -287,9 +274,9 @@ std::vector<std::shared_ptr<CollidingObject>> generateSolids(const std::shared_p switch (SCENE_ID) { case 1: - return generateSolidsScene1(scene); + return generateSolidsScene1(); case 2: - return generateSolidsScene2(scene); + return generateSolidsScene2(); case 3: return generateSolidsScene3(scene); case 4: diff --git a/Examples/SceneManagement/SceneManagementExample.cpp b/Examples/SceneManagement/SceneManagementExample.cpp index f0c4668a32b388d3994f06cae739ec753519ccd0..07b55ee9dd7ede77d3c1a63746ebccb553003201 100644 --- a/Examples/SceneManagement/SceneManagementExample.cpp +++ b/Examples/SceneManagement/SceneManagementExample.cpp @@ -20,9 +20,10 @@ =========================================================================*/ #include "imstkCamera.h" -#include "imstkCollisionGraph.h" +#include "imstkLogger.h" +#include "imstkNew.h" #include "imstkScene.h" -#include "imstkSimulationManager.h" +#include "imstkSceneManager.h" using namespace imstk; @@ -32,46 +33,49 @@ using namespace imstk; int main() { - auto simManager = std::make_shared<SimulationManager>(); + // Setup logger (write to file and stdout) + Logger::startLogger(); + + imstkNew<SceneManager> sceneManager; // Scenes LOG(INFO) << "-- Test add scenes"; - auto scene1 = std::make_shared<Scene>("scene1"); - simManager->addScene(scene1); - - simManager->createNewScene("scene2"); - auto scene2 = simManager->getScene("scene2"); - - auto scene3 = simManager->createNewScene(); - simManager->removeScene("Scene_3"); + imstkNew<Scene> scene1("scene1"); + scene1->initialize(); + sceneManager->addScene(scene1); + imstkNew<Scene> scene2("scene2"); + scene2->initialize(); + sceneManager->addScene(scene2); + + imstkNew<Scene> scene3("scene3"); + scene3->initialize(); + sceneManager->addScene(scene3); + sceneManager->removeScene("Scene3"); // switch LOG(INFO) << "-- Test scene switch"; - int delay = 5; - simManager->setActiveScene(scene1); - simManager->start(); + int delay = 1; + sceneManager->setActiveScene(scene1); + sceneManager->start(false); std::this_thread::sleep_for(std::chrono::seconds(delay)); - simManager->setActiveScene(scene2, false); + sceneManager->setActiveScene(scene2); std::this_thread::sleep_for(std::chrono::seconds(delay)); - simManager->setActiveScene(scene1, true); + sceneManager->setActiveScene(scene1); std::this_thread::sleep_for(std::chrono::seconds(delay)); - simManager->end(); + sceneManager->stop(true); // pause/run LOG(INFO) << "-- Test simulation pause/run"; - simManager->setActiveScene(scene2); - simManager->start(); + sceneManager->setActiveScene(scene2); + sceneManager->start(false); std::this_thread::sleep_for(std::chrono::seconds(delay)); - simManager->pause(); + sceneManager->pause(true); std::this_thread::sleep_for(std::chrono::seconds(delay)); - simManager->run(); + sceneManager->resume(true); std::this_thread::sleep_for(std::chrono::seconds(delay)); - simManager->pause(); + sceneManager->pause(true); std::this_thread::sleep_for(std::chrono::seconds(delay)); - simManager->end(); - - // Quit - while (simManager->getStatus() != SimulationStatus::Inactive) {} + sceneManager->stop(true); return 0; } diff --git a/Examples/Screenshot/ScreenshotExample.cpp b/Examples/Screenshot/ScreenshotExample.cpp index 9b88ed1ac828d23e7b2d9f4cca453a3d41cb9f6b..eabd59502c84462cfa6a53760fe3fbe934c27237 100644 --- a/Examples/Screenshot/ScreenshotExample.cpp +++ b/Examples/Screenshot/ScreenshotExample.cpp @@ -19,14 +19,22 @@ =========================================================================*/ -#include "imstkSimulationManager.h" -#include "imstkSceneObject.h" #include "imstkCamera.h" -#include "imstkLight.h" #include "imstkCube.h" -#include "imstkSphere.h" +#include "imstkKeyboardDeviceClient.h" +#include "imstkKeyboardSceneControl.h" +#include "imstkLight.h" +#include "imstkLogger.h" +#include "imstkMouseSceneControl.h" +#include "imstkNew.h" #include "imstkPlane.h" #include "imstkScene.h" +#include "imstkSceneManager.h" +#include "imstkSceneObject.h" +#include "imstkSphere.h" +#include "imstkViewer.h" +#include "imstkVTKScreenCaptureUtility.h" +#include "imstkVTKViewer.h" using namespace imstk; @@ -36,77 +44,100 @@ using namespace imstk; int main() { - // simManager and Scene - auto simManager = std::make_shared<SimulationManager>(); - auto sceneTest = simManager->createNewScene("ScreenShotUtility"); + // Setup logger (write to file and stdout) + Logger::startLogger(); + + imstkNew<Scene> scene("ScreenShotUtility"); // Plane - auto planeGeom = std::make_shared<Plane>(); - planeGeom->setWidth(10); - auto planeObj = std::make_shared<VisualObject>("VisualPlane"); + imstkNew<Plane> planeGeom; + planeGeom->setWidth(10.0); + imstkNew<VisualObject> planeObj("VisualPlane"); planeObj->setVisualGeometry(planeGeom); // Cube - auto cubeGeom = std::make_shared<Cube>(); + imstkNew<Cube> cubeGeom; cubeGeom->setWidth(0.5); cubeGeom->setPosition(1.0, -1.0, 0.5); // rotates could be replaced by cubeGeom->setOrientationAxis(1,1,1) (normalized inside) cubeGeom->rotate(UP_VECTOR, PI_4, Geometry::TransformType::ApplyToData); cubeGeom->rotate(RIGHT_VECTOR, PI_4, Geometry::TransformType::ApplyToData); - auto cubeObj = std::make_shared<VisualObject>("VisualCube"); + imstkNew<VisualObject> cubeObj("VisualCube"); cubeObj->setVisualGeometry(cubeGeom); // Sphere - auto sphereGeom = std::make_shared<Sphere>(); + imstkNew<Sphere> sphereGeom; sphereGeom->setRadius(0.3); - sphereGeom->setPosition(0, 2, 0); - auto sphereObj = std::make_shared<VisualObject>("VisualSphere"); + sphereGeom->setPosition(0.0, 2.0, 0.0); + imstkNew<VisualObject> sphereObj("VisualSphere"); sphereObj->setVisualGeometry(sphereGeom); // Light (white) - auto whiteLight = std::make_shared<PointLight>("whiteLight"); - whiteLight->setIntensity(100); - whiteLight->setPosition(Vec3d(5, 8, 5)); + imstkNew<PointLight> whiteLight("whiteLight"); + whiteLight->setIntensity(100.0); + whiteLight->setPosition(Vec3d(5.0, 8.0, 5.0)); // Light (red) - auto colorLight = std::make_shared<SpotLight>("colorLight"); - colorLight->setPosition(Vec3d(4, -3, 1)); - colorLight->setFocalPoint(Vec3d(0, 0, 0)); - colorLight->setIntensity(100); + imstkNew<SpotLight> colorLight("colorLight"); + colorLight->setPosition(Vec3d(4.0, -3.0, 1.0)); + colorLight->setFocalPoint(Vec3d(0.0, 0.0, 0.0)); + colorLight->setIntensity(100.0); colorLight->setColor(Color::Red); - colorLight->setSpotAngle(15); + colorLight->setSpotAngle(15.0); // Add in scene - sceneTest->addSceneObject(planeObj); - sceneTest->addSceneObject(cubeObj); - sceneTest->addSceneObject(sphereObj); - sceneTest->addLight(whiteLight); - sceneTest->addLight(colorLight); + scene->addSceneObject(planeObj); + scene->addSceneObject(cubeObj); + scene->addSceneObject(sphereObj); + scene->addLight(whiteLight); + scene->addLight(colorLight); // Update Camera - auto cam1 = sceneTest->getCamera(); - cam1->setPosition(Vec3d(-5.5, 2.5, 32)); - cam1->setFocalPoint(Vec3d(1, 1, 0)); - -#ifndef iMSTK_USE_Vulkan - auto viewer = simManager->getViewer(); - auto screenShotUtility - = std::dynamic_pointer_cast<VTKScreenCaptureUtility>(viewer->getScreenCaptureUtility()); - // Set up for screen shot - viewer->getScreenCaptureUtility()->setScreenShotPrefix("screenShot_"); - // Create a call back on key press of 'b' to take the screen shot - viewer->setOnCharFunction('b', [&](InteractorStyle* c) -> bool - { - screenShotUtility->saveScreenShot(); - return false; - }); -#endif + scene->getActiveCamera()->setPosition(Vec3d(-5.5, 2.5, 32.0)); + scene->getActiveCamera()->setFocalPoint(Vec3d(1.0, 1.0, 0.0)); - std::cout << "PRESS 'b' for taking screenshot" << std::endl; + LOG(INFO) << "PRESS 'b' for taking screenshots"; - // Run - simManager->setActiveScene(sceneTest); - simManager->start(SimulationStatus::Paused); + // Run the simulation + { + // Setup a viewer to render in its own thread + imstkNew<VTKViewer> viewer("Viewer"); + viewer->setActiveScene(scene); + viewer->getScreenCaptureUtility()->setScreenShotPrefix("screenShot_"); + + // Setup a scene manager to advance the scene in its own thread + imstkNew<SceneManager> sceneManager("Scene Manager"); + sceneManager->setActiveScene(scene); + viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer + + // Add mouse and keyboard controls to the viewer + { + imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice()); + mouseControl->setSceneManager(sceneManager); + viewer->addControl(mouseControl); + + imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice()); + keyControl->setSceneManager(sceneManager); + keyControl->setViewer(viewer); + viewer->addControl(keyControl); + + connect<KeyPressEvent>(viewer->getKeyboardDevice(), EventType::KeyPress, + [&](KeyPressEvent* e) + { + if (e->m_keyPressType == KEY_PRESS) + { + if (e->m_key == 'b') + { + viewer->getScreenCaptureUtility()->saveScreenShot(); + } + } + }); + } + + // Start viewer running, scene as paused + sceneManager->requestStatus(ThreadStatus::Paused); + viewer->start(); + } return 0; } diff --git a/Examples/TaskGraph/Configuration/taskGraphConfigureExample.cpp b/Examples/TaskGraph/Configuration/taskGraphConfigureExample.cpp index 3ff84e15cf6c4167f315b502258cc0dbb10a52a6..7af639db83878b108031c25b9c53d3195e684028 100644 --- a/Examples/TaskGraph/Configuration/taskGraphConfigureExample.cpp +++ b/Examples/TaskGraph/Configuration/taskGraphConfigureExample.cpp @@ -19,28 +19,33 @@ =========================================================================*/ -#include "imstkAPIUtilities.h" #include "imstkCamera.h" #include "imstkColorFunction.h" +#include "imstkKeyboardSceneControl.h" #include "imstkLight.h" #include "imstkLogger.h" +#include "imstkMouseSceneControl.h" +#include "imstkNew.h" #include "imstkPbdModel.h" #include "imstkPbdObject.h" +#include "imstkRenderMaterial.h" #include "imstkScene.h" -#include "imstkSimulationManager.h" +#include "imstkSceneManager.h" #include "imstkSurfaceMesh.h" #include "imstkTaskGraph.h" #include "imstkTaskGraphVizWriter.h" +#include "imstkVisualModel.h" +#include "imstkVTKViewer.h" using namespace imstk; -static std::unique_ptr<SurfaceMesh> +static std::shared_ptr<SurfaceMesh> makeClothGeometry( const double width, const double height, const int nRows, const int nCols) { // Create surface mesh - std::unique_ptr<SurfaceMesh> clothMesh = std::make_unique<SurfaceMesh>(); - StdVectorOfVec3d vertList; + imstkNew<SurfaceMesh> clothMesh; + StdVectorOfVec3d vertList; vertList.resize(nRows * nCols); const double dy = width / (double)(nCols - 1); @@ -93,10 +98,10 @@ makeClothObj(const std::string& name, double width, double height, int nRows, in { auto clothObj = std::make_shared<PbdObject>(name); - std::shared_ptr<SurfaceMesh> clothMesh(std::move(makeClothGeometry(width, height, nRows, nCols))); + std::shared_ptr<SurfaceMesh> clothMesh = makeClothGeometry(width, height, nRows, nCols); // Setup the Parameters - auto pbdParams = std::make_shared<PBDModelConfig>(); + imstkNew<PBDModelConfig> pbdParams; pbdParams->enableConstraint(PbdConstraint::Type::Distance, 1e2); pbdParams->enableConstraint(PbdConstraint::Type::Dihedral, 1e1); pbdParams->m_fixedNodeIds = { 0, static_cast<size_t>(nCols) - 1 }; @@ -106,12 +111,12 @@ makeClothObj(const std::string& name, double width, double height, int nRows, in pbdParams->m_iterations = 5; // Setup the Model - auto pbdModel = std::make_shared<PbdModel>(); + imstkNew<PbdModel> pbdModel; pbdModel->setModelGeometry(clothMesh); pbdModel->configure(pbdParams); // Setup the VisualModel - auto material = std::make_shared<RenderMaterial>(); + imstkNew<RenderMaterial> material; material->setBackFaceCulling(false); material->setColor(Color::LightGray); material->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface); @@ -133,8 +138,10 @@ makeClothObj(const std::string& name, double width, double height, int nRows, in int main() { - auto simManager = std::make_shared<SimulationManager>(); - auto scene = simManager->createNewScene("PBDCloth"); + // Setup logger (write to file and stdout) + Logger::startLogger(); + + imstkNew<Scene> scene("PBDCloth"); const double width = 10.0; const double height = 10.0; @@ -144,13 +151,13 @@ main() scene->addSceneObject(clothObj); // Adjust camera - scene->getCamera()->setFocalPoint(0, -5, 5); - scene->getCamera()->setPosition(-15., -5.0, 15.0); + scene->getActiveCamera()->setFocalPoint(0.0, -5.0, 5.0); + scene->getActiveCamera()->setPosition(-15.0, -5.0, 15.0); { // Setup some scalars - std::shared_ptr<SurfaceMesh> clothGeometry = std::dynamic_pointer_cast<SurfaceMesh>(clothObj->getPhysicsGeometry()); - std::shared_ptr<StdVectorOfReal> scalarsPtr = std::make_shared<StdVectorOfReal>(clothGeometry->getNumVertices()); + auto clothGeometry = std::dynamic_pointer_cast<SurfaceMesh>(clothObj->getPhysicsGeometry()); + auto scalarsPtr = std::make_shared<StdVectorOfReal>(clothGeometry->getNumVertices()); std::fill_n(scalarsPtr->data(), scalarsPtr->size(), 0.0); clothGeometry->setScalars(scalarsPtr); @@ -165,17 +172,19 @@ main() colorFunc->setRange(0.0, 2.0); material->setColorLookupTable(colorFunc); + // Adds a custom physics step to print out maximum velocity std::shared_ptr<PbdModel> pbdModel = clothObj->getPbdModel(); - scene->setTaskGraphConfigureCallback([&](Scene* scene) + connect<Event>(scene, EventType::Configure, + [&](Event*) { // Get the graph std::shared_ptr<TaskGraph> graph = scene->getTaskGraph(); // First write the graph before we make modifications, just to show the changes - TaskGraphVizWriter writer; - writer.setInput(graph); - writer.setFileName("taskGraphConfigureExampleOld.svg"); - writer.write(); + imstkNew<TaskGraphVizWriter> writer; + writer->setInput(graph); + writer->setFileName("taskGraphConfigureExampleOld.svg"); + writer->write(); // This node computes displacements and sets the color to the magnitude std::shared_ptr<TaskNode> computeVelocityScalars = std::make_shared<TaskNode>([&]() @@ -193,20 +202,42 @@ main() { scalars[i] = velocities[i].norm(); } - }, "ComputeVelocityScalars"); + }, "ComputeVelocityScalars"); // After IntegratePosition graph->insertAfter(clothObj->getUpdateGeometryNode(), computeVelocityScalars); // Write the modified graph - writer.setFileName("taskGraphConfigureExampleNew.svg"); - writer.write(); - }); + writer->setFileName("taskGraphConfigureExampleNew.svg"); + writer->write(); + }); } - // Start - simManager->setActiveScene(scene); - simManager->start(SimulationStatus::Paused); + // Run the simulation + { + // Setup a viewer to render in its own thread + imstkNew<VTKViewer> viewer("Viewer"); + viewer->setActiveScene(scene); + + // Setup a scene manager to advance the scene in its own thread + imstkNew<SceneManager> sceneManager("Scene Manager"); + sceneManager->setActiveScene(scene); + viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer + + // Add mouse and keyboard controls to the viewer + { + imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice()); + mouseControl->setSceneManager(sceneManager); + viewer->addControl(mouseControl); + + imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice()); + keyControl->setSceneManager(sceneManager); + keyControl->setViewer(viewer); + viewer->addControl(keyControl); + } + + viewer->start(); + } return 0; } diff --git a/Examples/TaskGraph/TaskGraph/taskGraphExample.cpp b/Examples/TaskGraph/TaskGraph/taskGraphExample.cpp index c05cf60888a790e16c442768eef771f22410ca16..8ddaf56551729f561be9a3adadceb47f991d21d5 100644 --- a/Examples/TaskGraph/TaskGraph/taskGraphExample.cpp +++ b/Examples/TaskGraph/TaskGraph/taskGraphExample.cpp @@ -19,11 +19,12 @@ =========================================================================*/ +#include "imstkNew.h" #include "imstkParallelFor.h" #include "imstkSequentialTaskGraphController.h" #include "imstkTaskGraph.h" #include "imstkTbbTaskGraphController.h" -#include <iostream> +#include "imstkLogger.h" using namespace imstk; @@ -33,6 +34,8 @@ using namespace imstk; int main() { + Logger::startLogger(); + const bool runExampleInParallel = true; // Initialize some data arrays @@ -58,17 +61,19 @@ main() int sumB = 0; // Now create a graph that computes results = sum_i(x_i + y_i) * sum_i(w_i * z_i) - std::shared_ptr<TaskGraph> graph = std::make_shared<TaskGraph>(); + imstkNew<TaskGraph> graph; // Create and add the nodes - std::shared_ptr<TaskNode> addNode = graph->addFunction("Add Step", [&]() + std::shared_ptr<TaskNode> addNode = graph->addFunction("Add Step", + [&]() { for (int i = 0; i < countA; i++) { sumA += (x[i] + y[i]); } }); - std::shared_ptr<TaskNode> multNode = graph->addFunction("Mult Step", [&]() + std::shared_ptr<TaskNode> multNode = graph->addFunction("Mult Step", + [&]() { for (int i = 0; i < countB; i++) { @@ -97,11 +102,11 @@ main() controller->setTaskGraph(graph); if (!controller->initialize()) { - std::cout << "TaskGraph failed to initialize" << std::endl; + LOG(FATAL) << "TaskGraph failed to initialize"; return 1; } controller->execute(); - std::cout << "Results: " << sumA + sumB << std::endl; + LOG(INFO) << "Results: " << sumA + sumB; return 0; } diff --git a/Examples/TaskGraph/Timing/taskGraphTimingExample.cpp b/Examples/TaskGraph/Timing/taskGraphTimingExample.cpp index e5f8032c118763301345c8f40e51c6e77f82bc4a..72a3d144c69a3e395ffda2aa499bc5b8ed31487f 100644 --- a/Examples/TaskGraph/Timing/taskGraphTimingExample.cpp +++ b/Examples/TaskGraph/Timing/taskGraphTimingExample.cpp @@ -19,15 +19,20 @@ limitations under the License. =========================================================================*/ -#include "imstkAPIUtilities.h" #include "imstkCamera.h" +#include "imstkKeyboardSceneControl.h" #include "imstkLineMesh.h" +#include "imstkLogger.h" +#include "imstkMouseSceneControl.h" +#include "imstkNew.h" #include "imstkPbdModel.h" #include "imstkPbdObject.h" +#include "imstkRenderMaterial.h" #include "imstkScene.h" #include "imstkSceneManager.h" -#include "imstkSimulationManager.h" #include "imstkTaskGraphVizWriter.h" +#include "imstkVisualModel.h" +#include "imstkVTKViewer.h" using namespace imstk; @@ -38,7 +43,7 @@ static std::shared_ptr<LineMesh> makeStringGeometry(const Vec3d& pos, const size_t numVerts, const double stringLength) { // Create the geometry - std::shared_ptr<LineMesh> stringGeometry = std::make_shared<LineMesh>(); + imstkNew<LineMesh> stringGeometry; StdVectorOfVec3d vertList; vertList.resize(numVerts); @@ -74,13 +79,13 @@ makePbdString( const double bendStiffness, const Color& color) { - std::shared_ptr<PbdObject> stringObj = std::make_shared<PbdObject>(name); + imstkNew<PbdObject> stringObj(name); // Setup the Geometry std::shared_ptr<LineMesh> stringMesh = makeStringGeometry(pos, numVerts, stringLength); // Setup the Parameters - auto pbdParams = std::make_shared<PBDModelConfig>(); + imstkNew<PBDModelConfig> pbdParams; pbdParams->enableConstraint(PbdConstraint::Type::Distance, 1e7); pbdParams->enableConstraint(PbdConstraint::Type::Bend, bendStiffness); pbdParams->m_fixedNodeIds = { 0 }; @@ -90,18 +95,18 @@ makePbdString( pbdParams->m_iterations = 5; // Setup the Model - std::shared_ptr<PbdModel> pbdModel = std::make_shared<PbdModel>(); + imstkNew<PbdModel> pbdModel; pbdModel->setModelGeometry(stringMesh); pbdModel->configure(pbdParams); // Setup the VisualModel - std::shared_ptr<RenderMaterial> material = std::make_shared<RenderMaterial>(); + imstkNew<RenderMaterial> material; material->setBackFaceCulling(false); material->setEdgeColor(color); material->setLineWidth(2.0f); material->setDisplayMode(RenderMaterial::DisplayMode::Wireframe); - std::shared_ptr<VisualModel> visualModel = std::make_shared<VisualModel>(stringMesh); + imstkNew<VisualModel> visualModel(stringMesh); visualModel->setRenderMaterial(material); // Setup the Object @@ -158,27 +163,28 @@ const Color endColor = Color(0.0, 1.0, 0.0); // Color of last string int main() { - auto simManager = std::make_shared<SimulationManager>(); - auto scene = simManager->createNewScene("PBDString"); + // Setup logger (write to file and stdout) + Logger::startLogger(); + + imstkNew<Scene> scene("PBDString"); scene->getConfig()->taskTimingEnabled = true; // Setup N separate strings with varying bend stiffnesses std::vector<std::shared_ptr<PbdObject>> pbdStringObjs = makePbdStrings(numStrings, numVerts, stringSpacing, stringLength, startColor, endColor); - // Add them to the scene + // Add the string scene objects to the scene for (std::shared_ptr<PbdObject> obj : pbdStringObjs) { scene->addSceneObject(obj); } // Adjust the camera - scene->getCamera()->setFocalPoint(0.0, 0.0, 0.0); - scene->getCamera()->setPosition(0.0, 0.0, 15.0); + scene->getActiveCamera()->setPosition(0.0, 0.0, 15.0); // Move the points every frame double t = 0.0; auto movePoints = - [&pbdStringObjs, &t](Module* module) + [&pbdStringObjs, &t](Event*) { for (unsigned int i = 0; i < pbdStringObjs.size(); i++) { @@ -186,27 +192,51 @@ main() const Vec3d pos = model->getCurrentState()->getVertexPosition(0); // Move in circle, derivatives of parametric eq of circle const Vec3d newPos = Vec3d( - pos.x() + -std::sin(t) * radius * dt, - pos.y(), - pos.z() + std::cos(t) * radius * dt); + pos.x() + -std::sin(t) * radius * dt, + pos.y(), + pos.z() + std::cos(t) * radius * dt); model->getCurrentState()->setVertexPosition(0, newPos); } t += dt; }; - simManager->getSceneManager(scene)->setPostUpdateCallback(movePoints); - // Start - simManager->setActiveScene(scene); - simManager->start(); + // Run the simulation + { + // Setup a viewer to render in its own thread + imstkNew<VTKViewer> viewer("Viewer"); + viewer->setActiveScene(scene); + + // Setup a scene manager to advance the scene in its own thread + imstkNew<SceneManager> sceneManager("Scene Manager"); + sceneManager->setActiveScene(scene); + viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer + connect<Event>(sceneManager, EventType::PostUpdate, movePoints); + + // Add mouse and keyboard controls to the viewer + { + imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice()); + mouseControl->setSceneManager(sceneManager); + viewer->addControl(mouseControl); + + imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice()); + keyControl->setSceneManager(sceneManager); + keyControl->setViewer(viewer); + viewer->addControl(keyControl); + } + + // Start viewer running, scene as paused + sceneManager->requestStatus(ThreadStatus::Paused); + viewer->start(); + } // Write the graph, highlighting the critical path and putting the completion time in the name - TaskGraphVizWriter writer; - writer.setInput(scene->getTaskGraph()); - writer.setFileName("taskGraphBenchmarkExample.svg"); - writer.setHighlightCriticalPath(true); - writer.setWriteNodeComputeTimesColor(true); - writer.setWriteNodeComputeTimesText(true); - writer.write(); + imstkNew<TaskGraphVizWriter> writer; + writer->setInput(scene->getTaskGraph()); + writer->setFileName("taskGraphBenchmarkExample.svg"); + writer->setHighlightCriticalPath(true); + writer->setWriteNodeComputeTimesColor(true); + writer->setWriteNodeComputeTimesText(true); + writer->write(); return 0; } diff --git a/Examples/Vessel/CMakeLists.txt b/Examples/Vessel/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..20f0c976deb06b7dec067492d1a9e25cef911220 --- /dev/null +++ b/Examples/Vessel/CMakeLists.txt @@ -0,0 +1,34 @@ +########################################################################### +# +# Copyright (c) Kitware, Inc. +# +# 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. +# +########################################################################### + +project(Example-Vessel) + +#----------------------------------------------------------------------------- +# Create executable +#----------------------------------------------------------------------------- +imstk_add_executable(${PROJECT_NAME} vesselExample.cpp) + +#----------------------------------------------------------------------------- +# Add the target to Examples folder +#----------------------------------------------------------------------------- +SET_TARGET_PROPERTIES (${PROJECT_NAME} PROPERTIES FOLDER Examples) + +#----------------------------------------------------------------------------- +# Link libraries to executable +#----------------------------------------------------------------------------- +target_link_libraries(${PROJECT_NAME} SimulationManager Filtering) diff --git a/Examples/Vessel/vesselExample.cpp b/Examples/Vessel/vesselExample.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b8ef58135b5fc2fe5b33f2cfe1af366a4176f7bf --- /dev/null +++ b/Examples/Vessel/vesselExample.cpp @@ -0,0 +1,279 @@ +/*========================================================================= + + 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 "imstkCamera.h" +#include "imstkCollisionGraph.h" +#include "imstkDataArray.h" +#include "imstkImageData.h" +#include "imstkImageDistanceTransform.h" +#include "imstkKeyboardSceneControl.h" +#include "imstkLight.h" +#include "imstkMeshIO.h" +#include "imstkMouseSceneControl.h" +#include "imstkNew.h" +#include "imstkRenderMaterial.h" +#include "imstkScene.h" +#include "imstkSceneManager.h" +#include "imstkSignedDistanceField.h" +#include "imstkSPHModel.h" +#include "imstkSPHObject.h" +#include "imstkSphObjectCollisionPair.h" +#include "imstkSurfaceMesh.h" +#include "imstkSurfaceMeshDistanceTransform.h" +#include "imstkSurfaceMeshImageMask.h" +#include "imstkViewer.h" +#include "imstkVisualModel.h" +#include "imstkVTKViewer.h" + +using namespace imstk; + +/// +/// \brief Generate a volume of fluid with the specified SurfaceMesh +/// +static std::shared_ptr<StdVectorOfVec3d> +generateFluidVolume(const double particleRadius, std::shared_ptr<SurfaceMesh> spawnSurfaceVolume) +{ + Vec3d minima, maxima; + spawnSurfaceVolume->computeBoundingBox(minima, maxima); + + double particleDiameter = particleRadius * 2.0; + const Vec3d size = (maxima - minima) + Vec3d(particleDiameter, particleDiameter, particleDiameter); + Vec3i dim = size.cwiseProduct(Vec3d(1.0 / particleDiameter, 1.0 / particleDiameter, 1.0 / particleDiameter)).cast<int>(); + + // Compute the binary mask + imstkNew<SurfaceMeshImageMask> makeBinaryMask; + makeBinaryMask->setInputMesh(spawnSurfaceVolume); + makeBinaryMask->setDimensions(dim[0], dim[1], dim[2]); + makeBinaryMask->update(); + + // Compute the DT (won't perfectly conform to surface as we used a binary mask) + imstkNew<ImageDistanceTransform> distTransformFromMask; + distTransformFromMask->setInputImage(makeBinaryMask->getOutputImage()); + distTransformFromMask->update(); + + std::shared_ptr<DataArray<float>> scalarsPtr = std::dynamic_pointer_cast<DataArray<float>>(distTransformFromMask->getOutputImage()->getScalars()); + const DataArray<float>& scalars = *scalarsPtr; + const Vec3i& dim1 = makeBinaryMask->getOutputImage()->getDimensions(); + const Vec3d& spacing = makeBinaryMask->getOutputImage()->getSpacing(); + const Vec3d& shift = makeBinaryMask->getOutputImage()->getOrigin() + spacing * 0.5; + const double threshold = particleDiameter * 1.0; // How far from the boundary to accept particles + + imstkNew<StdVectorOfVec3d> particles; + particles->reserve(dim1[0] * dim1[1] * dim1[2]); + + int i = 0; + for (int z = 0; z < dim1[2]; z++) + { + for (int y = 0; y < dim1[1]; y++) + { + for (int x = 0; x < dim1[0]; x++, i++) + { + if (x > 1 && y > 1 && z > 1 && scalars[i] < -threshold) + { + particles->push_back(Vec3d(x, y, z).cwiseProduct(spacing) + shift); + } + } + } + } + particles->shrink_to_fit(); + return particles; +} + +static std::shared_ptr<SPHObject> +makeSPHObject(const std::string& name, const double particleRadius, const double particleSpacing) +{ + // Create the sph object + imstkNew<SPHObject> fluidObj(name); + + // Setup the Geometry + auto spawnMesh = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/legs/femoralArteryCut.stl"); + // By spacing them slightly closer we can induce larger compression at the start + std::shared_ptr<StdVectorOfVec3d> particles = generateFluidVolume(particleSpacing, spawnMesh); + LOG(INFO) << "Number of particles: " << particles->size(); + imstkNew<PointSet> fluidGeometry; + fluidGeometry->initialize(*particles); + + // Setup the Parameters + imstkNew<SPHModelConfig> sphParams(particleRadius); + sphParams->m_bNormalizeDensity = true; + sphParams->m_kernelOverParticleRadiusRatio = 6.0; + sphParams->m_viscosityCoeff = 0.8; + sphParams->m_surfaceTensionStiffness = 5.0; + sphParams->m_frictionBoundary = 0.1; + + // Setup the Model + imstkNew<SPHModel> sphModel; + sphModel->setModelGeometry(fluidGeometry); + sphModel->configure(sphParams); + sphModel->setTimeStepSizeType(TimeSteppingType::RealTime); + + // Setup the VisualModel + imstkNew<VisualModel> fluidVisualModel(fluidGeometry.get()); + imstkNew<RenderMaterial> fluidMaterial; + fluidMaterial->setDisplayMode(RenderMaterial::DisplayMode::Fluid); + fluidMaterial->setPointSize(particleRadius * 2.0f); // For fluids + fluidVisualModel->setRenderMaterial(fluidMaterial); + + // Setup the Object + fluidObj->setDynamicalModel(sphModel); + fluidObj->addVisualModel(fluidVisualModel); + fluidObj->setCollidingGeometry(fluidGeometry); + fluidObj->setPhysicsGeometry(fluidGeometry); + + return fluidObj; +} + +static std::shared_ptr<CollidingObject> +makeLegs(const std::string& name, const Vec3d& position) +{ + // Create the pbd object + imstkNew<CollidingObject> legsObj(name); + + // Setup the Geometry (read dragon mesh) + auto legsMesh = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/legs/legsCutaway.stl"); + auto bonesMesh = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/legs/legsBones.stl"); + auto femoralMesh = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/legs/femoralArtery.stl"); + auto collisionMesh = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/legs/femoralArteryCut.stl"); + + // Setup the Legs VisualModel + imstkNew<VisualModel> legsMeshModel(legsMesh); + imstkNew<RenderMaterial> legsMaterial; + legsMaterial->setDisplayMode(RenderMaterial::DisplayMode::Surface); + legsMaterial->setOpacity(0.85f); + legsMaterial->setDiffuseColor(Color(0.8, 0.688, 0.396)); + legsMeshModel->setRenderMaterial(legsMaterial); + + // Setup the Bones VisualModel + imstkNew<VisualModel> bonesMeshModel(bonesMesh); + imstkNew<RenderMaterial> bonesMaterial; + bonesMaterial->setDisplayMode(RenderMaterial::DisplayMode::Surface); + bonesMaterial->setDiffuseColor(Color(0.538, 0.538, 0.538)); + bonesMeshModel->setRenderMaterial(bonesMaterial); + + // Setup the Femoral VisualModel + imstkNew<VisualModel> femoralMeshModel(femoralMesh); + imstkNew<RenderMaterial> femoralMaterial; + femoralMaterial->setDisplayMode(RenderMaterial::DisplayMode::Surface); + femoralMaterial->setOpacity(0.2f); + femoralMaterial->setDiffuseColor(Color(0.8, 0.119, 0.180)); + femoralMeshModel->setRenderMaterial(femoralMaterial); + + // Setup the Object + legsObj->addVisualModel(legsMeshModel); + legsObj->addVisualModel(bonesMeshModel); + legsObj->addVisualModel(femoralMeshModel); + + LOG(INFO) << "Computing SDF"; + imstkNew<SurfaceMeshDistanceTransform> computeSdf; + computeSdf->setInputMesh(collisionMesh); + computeSdf->setDimensions(100, 100, 100); + Vec3d min, max; + collisionMesh->computeBoundingBox(min, max); + const Vec3d size = max - min; + Vec6d bounds; + bounds[0] = min[0] - size[0] * 0.25; + bounds[1] = max[0] + size[0] * 0.25; + bounds[2] = min[1] - size[1] * 0.25; + bounds[3] = max[1] + size[1] * 0.25; + 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())); + + return legsObj; +} + +/// +/// \brief This example demonstrates interaction simulates SPH fluid contained within +/// an SDF vessel +/// +int +main() +{ + // Setup logger (write to file and stdout) + Logger::startLogger(); + + imstkNew<Scene> scene("Vessel"); + + // Setup the scene + { + //scene->getConfig()->taskTimingEnabled = true; + + // Static Dragon object + std::shared_ptr<CollidingObject> legsObj = makeLegs("Vessel", Vec3d(0.0, 0.0, 0.0)); + scene->addSceneObject(legsObj); + + // Position the camera + const Vec6d& bounds = std::dynamic_pointer_cast<SignedDistanceField>(legsObj->getCollidingGeometry())->getBounds(); + const Vec3d center = (Vec3d(bounds[0], bounds[2], bounds[4]) + Vec3d(bounds[1], bounds[3], bounds[5])) * 0.5; + scene->getActiveCamera()->setPosition(3.25, 1.6, 3.38); + scene->getActiveCamera()->setFocalPoint(-2.05, 1.89, -1.32); + scene->getActiveCamera()->setViewUp(-0.66, 0.01, 0.75); + + // SPH fluid box overtop the dragon + std::shared_ptr<SPHObject> sphObj = makeSPHObject("Fluid", 0.004, 0.0035); + scene->addSceneObject(sphObj); + + // Interaction + imstkNew<SphObjectCollisionPair> collisionInteraction(sphObj, legsObj, CollisionDetection::Type::PointSetToImplicit); + scene->getCollisionGraph()->addInteraction(collisionInteraction); + + // Light + imstkNew<DirectionalLight> light("light"); + light->setDirection(0.0, 1.0, -1.0); + light->setIntensity(1.0); + scene->addLight(light); + } + + // Run the simulation + { + // Setup a viewer to render in its own thread + imstkNew<VTKViewer> viewer("Viewer"); + viewer->setActiveScene(scene); + viewer->setBackgroundColors(Vec3d(0.3285, 0.3285, 0.6525), Vec3d(0.13836, 0.13836, 0.2748), true); + + // Setup a scene manager to advance the scene in its own thread + imstkNew<SceneManager> sceneManager("Scene Manager"); + sceneManager->setActiveScene(scene); + viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer + + // Add mouse and keyboard controls to the viewer + { + imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice()); + mouseControl->setSceneManager(sceneManager); + viewer->addControl(mouseControl); + + imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice()); + keyControl->setSceneManager(sceneManager); + keyControl->setViewer(viewer); + viewer->addControl(keyControl); + } + + // Start viewer running, scene as paused + sceneManager->requestStatus(ThreadStatus::Paused); + viewer->start(); + } + + return 0; +} diff --git a/Examples/VirtualCoupling/VirtualCouplingExample.cpp b/Examples/VirtualCoupling/VirtualCouplingExample.cpp index a59c63db9860f6db1cfe48c6c89c9416a80b61ee..7d2253acb84c707cefc6c5211abb8503e9782786 100644 --- a/Examples/VirtualCoupling/VirtualCouplingExample.cpp +++ b/Examples/VirtualCoupling/VirtualCouplingExample.cpp @@ -19,21 +19,30 @@ =========================================================================*/ -#include "imstkSimulationManager.h" -#include "imstkVirtualCouplingCH.h" -#include "imstkHDAPIDeviceServer.h" -#include "imstkHDAPIDeviceClient.h" -#include "imstkSceneObjectController.h" -#include "imstkDeviceTracker.h" +#include "imstkCamera.h" +#include "imstkCDObjectFactory.h" +#include "imstkCollidingObject.h" +#include "imstkCollisionData.h" #include "imstkCollisionGraph.h" +#include "imstkCollisionPair.h" +#include "imstkHapticDeviceClient.h" +#include "imstkHapticDeviceManager.h" +#include "imstkKeyboardSceneControl.h" #include "imstkLight.h" -#include "imstkCamera.h" +#include "imstkMouseSceneControl.h" +#include "imstkNew.h" #include "imstkPlane.h" -#include "imstkSphere.h" +#include "imstkRenderMaterial.h" #include "imstkScene.h" +#include "imstkSceneManager.h" +#include "imstkSceneObjectController.h" +#include "imstkSphere.h" +#include "imstkVirtualCouplingCH.h" +#include "imstkVisualModel.h" +#include "imstkVTKViewer.h" // global variables -const std::string phantomOmni1Name = "Phantom1"; +const std::string phantomOmni1Name = "Default Device"; using namespace imstk; @@ -44,46 +53,35 @@ using namespace imstk; int main() { -#ifndef iMSTK_USE_OPENHAPTICS - std::cout << "LaparoscopicToolController example needs haptic device to be enabled at build time" << std::endl; - return 1; -#else if - // simManager and Scene - auto simManager = std::make_shared<SimulationManager>(); - auto scene = simManager->createNewScene("VirtualCoupling"); + // Setup logger (write to file and stdout) + Logger::startLogger(); + + // Scene + imstkNew<Scene> scene("VirtualCoupling"); // Create a plane in the scene - auto planeGeom = std::make_shared<Plane>(); - planeGeom->setWidth(400); - planeGeom->setPosition(0.0, -50, 0.0); - auto planeObj = std::make_shared<CollidingObject>("Plane"); + auto planeGeom = std::make_shared<Plane>(); + imstkNew<Plane> plane(Vec3d(0.0, -50.0, 0.0)); + planeGeom->setWidth(400.0); + imstkNew<CollidingObject> planeObj("Plane"); planeObj->setVisualGeometry(planeGeom); planeObj->setCollidingGeometry(planeGeom); scene->addSceneObject(planeObj); // Create the virtual coupling object controller - // Device clients - auto client = std::make_shared<HDAPIDeviceClient>(phantomOmni1Name); - // Device Server - auto server = std::make_shared<HDAPIDeviceServer>(); - server->addDeviceClient(client); - simManager->addModule(server); - - // Device tracker - auto deviceTracker = std::make_shared<DeviceTracker>(client); + imstkNew<HapticDeviceManager> server; + std::shared_ptr<HapticDeviceClient> client = server->makeDeviceClient(phantomOmni1Name); // Create a virtual coupling object - auto visualGeom = std::make_shared<Sphere>(); - visualGeom->setRadius(20); - auto collidingGeom = std::make_shared<Sphere>(); - collidingGeom->setRadius(20); - auto obj = std::make_shared<CollidingObject>("VirtualCouplingObject"); + imstkNew<Sphere> visualGeom(Vec3d(0.0, 0.0, 0.0), 20.0); + imstkNew<Sphere> collidingGeom(Vec3d(0.0, 0.0, 0.0), 20.0); + imstkNew<CollidingObject> obj("VirtualCouplingObject"); obj->setCollidingGeometry(collidingGeom); - auto material = std::make_shared<RenderMaterial>(); - auto visualModel = std::make_shared<VisualModel>(visualGeom); + imstkNew<RenderMaterial> material; + imstkNew<VisualModel> visualModel(visualGeom.get()); visualModel->setRenderMaterial(material); obj->addVisualModel(visualModel); @@ -91,39 +89,64 @@ main() scene->addSceneObject(obj); // Create and add virtual coupling object controller in the scene - auto objController = std::make_shared<SceneObjectController>(obj, deviceTracker); - scene->addObjectController(objController); + imstkNew<SceneObjectController> controller(obj, client); + scene->addController(controller); { // Setup CD, and collision data - auto colData = std::make_shared<CollisionData>(); + imstkNew<CollisionData> colData; + std::shared_ptr<CollisionDetection> colDetect = makeCollisionDetectionObject(CollisionDetection::Type::UnidirectionalPlaneToSphere, - planeObj, obj, colData); + planeObj->getCollidingGeometry(), obj->getCollidingGeometry(), colData); // Setup the handler - auto colHandler = std::make_shared<VirtualCouplingCH>(CollisionHandling::Side::B, colData, planeObj, obj); + imstkNew<VirtualCouplingCH> colHandler(CollisionHandling::Side::B, colData, obj); colHandler->setStiffness(5e-01); colHandler->setDamping(0.005); - auto pair = std::make_shared<CollisionPair>(planeObj, obj, colDetect, nullptr, colHandler); - scene->getCollisionGraph()->addInteractionPair(pair); + imstkNew<CollisionPair> pair(planeObj, obj, colDetect, nullptr, colHandler); + scene->getCollisionGraph()->addInteraction(pair); } // Camera - auto cam = scene->getCamera(); - cam->setPosition(Vec3d(200, 200, 200)); - cam->setFocalPoint(Vec3d(0, 0, 0)); + scene->getActiveCamera()->setPosition(Vec3d(200, 200, 200)); + scene->getActiveCamera()->setFocalPoint(Vec3d(0, 0, 0)); // Light - auto light = std::make_shared<DirectionalLight>("light"); - light->setFocalPoint(Vec3d(5, -8, -5)); - light->setIntensity(1); + imstkNew<DirectionalLight> light("light"); + light->setFocalPoint(Vec3d(5.0, -8.0, -5.0)); + light->setIntensity(1.0); scene->addLight(light); - //Run - simManager->setActiveScene(scene); - simManager->start(SimulationStatus::Running); + //Run the simulation + { + // Setup a viewer to render in its own thread + imstkNew<VTKViewer> viewer("Viewer 1"); + viewer->setActiveScene(scene); + + // Setup a scene manager to advance the scene in its own thread + imstkNew<SceneManager> sceneManager("Scene Manager 1"); + sceneManager->setActiveScene(scene); + viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer + + viewer->addChildThread(server); + + // Add mouse and keyboard controls to the viewer + { + imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice()); + mouseControl->setSceneManager(sceneManager); + viewer->addControl(mouseControl); + + imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice()); + keyControl->setSceneManager(sceneManager); + keyControl->setViewer(viewer); + viewer->addControl(keyControl); + } + + // Start viewer running, scene as paused + sceneManager->requestStatus(ThreadStatus::Paused); + viewer->start(); + } return 0; -#endif } diff --git a/Examples/VolumeRendering/CMakeLists.txt b/Examples/VolumeRendering/CMakeLists.txt index db6393841ce748a029762a5e57238f2a50a660d4..dc3e9e015f50de8a6ff4b43bfd6ea6440622740f 100644 --- a/Examples/VolumeRendering/CMakeLists.txt +++ b/Examples/VolumeRendering/CMakeLists.txt @@ -36,4 +36,4 @@ SET_TARGET_PROPERTIES (${PROJECT_NAME} PROPERTIES FOLDER Examples) #----------------------------------------------------------------------------- # Link libraries to executable #----------------------------------------------------------------------------- -target_link_libraries(${PROJECT_NAME} SimulationManager apiUtilities) +target_link_libraries(${PROJECT_NAME} SimulationManager apiUtilities Filtering) diff --git a/Examples/VolumeRendering/VolumeRenderingExample.cpp b/Examples/VolumeRendering/VolumeRenderingExample.cpp index 97e96ed9d5527c3da31378a4784be155fa2cfc97..b67ad55f671d44c16a2600c02674a033d3671ef5 100644 --- a/Examples/VolumeRendering/VolumeRenderingExample.cpp +++ b/Examples/VolumeRendering/VolumeRenderingExample.cpp @@ -9,7 +9,7 @@ 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 + 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, @@ -19,21 +19,21 @@ =========================================================================*/ -// imstk -#include "imstkAPIUtilities.h" #include "imstkCamera.h" +#include "imstkImageData.h" +#include "imstkKeyboardSceneControl.h" #include "imstkMeshIO.h" -#include "imstkSimulationManager.h" +#include "imstkMouseSceneControl.h" +#include "imstkNew.h" +#include "imstkScene.h" +#include "imstkSceneManager.h" +#include "imstkSceneObject.h" +#include "imstkVisualModel.h" #include "imstkVolumeRenderMaterial.h" #include "imstkVolumeRenderMaterialPresets.h" -#include "imstkVTKTextStatusManager.h" -#include "imstkSceneManager.h" -#include "imstkScene.h" #include "imstkVTKRenderer.h" - -// STL -#include <sstream> -#include <string> +#include "imstkVTKTextStatusManager.h" +#include "imstkVTKViewer.h" using namespace imstk; @@ -44,35 +44,35 @@ int main() { // SDK and Scene - auto simManager = std::make_shared<SimulationManager>(); - auto scene = simManager->createNewScene("VolumeRendering"); - simManager->setActiveScene(scene); + imstkNew<Scene> scene("VolumeRendering"); - // Use MeshIO to read the image dataset - auto imageData = imstk::MeshIO::read(iMSTK_DATA_ROOT "skullVolume.nrrd"); // Create a visual object in the scene for the volume - auto volumeObj = std::make_shared<imstk::VisualObject>("VisualVolume"); + imstkNew<VisualObject> volumeObj("VisualVolume"); + auto imageData = MeshIO::read<ImageData>(iMSTK_DATA_ROOT "skullVolume.nrrd"); volumeObj->setVisualGeometry(imageData); scene->addSceneObject(volumeObj); // Update Camera to position volume close to viewer - auto cam = scene->getCamera(); - cam->setPosition(Vec3d(0, -200, -50)); - cam->setFocalPoint(Vec3d(0, 0, -50)); + auto cam = scene->getActiveCamera(); + cam->setPosition(Vec3d(0.0, -200.0, -100.0)); + cam->setFocalPoint(Vec3d(0.0, 0.0, -50.0)); cam->setViewUp(Vec3d(0.02, 0.4, 0.9)); int count = 0; - // Get VTK Renderer - auto viewer = std::dynamic_pointer_cast<VTKViewer>(simManager->getViewer()); + + // Setup a viewer to render in its own thread + imstkNew<VTKViewer> viewer("Viewer"); + viewer->setActiveScene(scene); + auto renderer = std::dynamic_pointer_cast<VTKRenderer>(viewer->getActiveRenderer()); renderer->updateBackground(Vec3d(0.3285, 0.3285, 0.6525), Vec3d(0.13836, 0.13836, 0.2748), true); auto statusManager = viewer->getTextStatusManager(); - statusManager->setStatusFontSize(VTKTextStatusManager::Custom, 30); - statusManager->setStatusDisplayCorner(VTKTextStatusManager::Custom, VTKTextStatusManager::DisplayCorner::UpperLeft); + statusManager->setStatusFontSize(VTKTextStatusManager::StatusType::Custom, 30); + statusManager->setStatusDisplayCorner(VTKTextStatusManager::StatusType::Custom, VTKTextStatusManager::DisplayCorner::UpperLeft); auto updateFunc = - [&](Module*) { + [&](Event*) { if (count % 2) { // Change the render material every other frame @@ -101,9 +101,29 @@ main() // Delay to show the past frame std::this_thread::sleep_for(std::chrono::milliseconds(2000)); }; - simManager->getSceneManager(scene)->setPreUpdateCallback(updateFunc); - // Run - simManager->start(); + + // Run the simulation + { + // Setup a scene manager to advance the scene in its own thread + imstkNew<SceneManager> sceneManager("Scene Manager"); + sceneManager->setActiveScene(scene); + viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer + connect<Event>(sceneManager, EventType::PostUpdate, updateFunc); + + // Add mouse and keyboard controls to the viewer + { + imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice()); + mouseControl->setSceneManager(sceneManager); + viewer->addControl(mouseControl); + + imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice()); + keyControl->setSceneManager(sceneManager); + keyControl->setViewer(viewer); + viewer->addControl(keyControl); + } + + viewer->start(); + } return 0; } diff --git a/README.md b/README.md index e2bc6473fe8d703593d6213b6b023c31095adbde..1657e989537780be5215d18cd2e8b0281d5ef6fc 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ - [CeMSIM-Rensselaer Polytechnic Institute](http://cemsim.rpi.edu/) - [University of Central Arkansas](http://sun0.cs.uca.edu/~thalic/virasim.html) -####Funding support: +### Funding support: This project is supported in part by the following grants [9R44OD018334](https://www.sbir.gov/sbirsearch/detail/1032259), [1R44EB019802](https://www.sbir.gov/sbirsearch/detail/1047037), [1R44AR075481](https://projectreporter.nih.gov/project_info_details.cfm?aid=9777225&icde=50531419) , [1R01EB025247](https://projectreporter.nih.gov/project_info_details.cfm?aid=9738646&icde=50531433), [2R44DK115332](https://projectreporter.nih.gov/project_info_details.cfm?aid=9843084&icde=50531443) Disclaimer: The content is solely the responsibility of the authors and does not necessarily represent the official views of the NIH and its institutes. diff --git a/Source/Animation/Particles/imstkRenderParticleEmitter.cpp b/Source/Animation/Particles/imstkRenderParticleEmitter.cpp index 0cf3c618e03203587e5126221bbb6b9eb36918cf..627dc6cc39a02512208893d722ce2693a7c614b3 100644 --- a/Source/Animation/Particles/imstkRenderParticleEmitter.cpp +++ b/Source/Animation/Particles/imstkRenderParticleEmitter.cpp @@ -20,22 +20,20 @@ =========================================================================*/ #include "imstkRenderParticleEmitter.h" -#include "imstkColor.h" #include "imstkLogger.h" +#include "imstkRenderParticles.h" +#include "imstkTimer.h" namespace imstk { RenderParticleEmitter::RenderParticleEmitter(std::shared_ptr<Geometry> geometry, const float time /*= 3000*/, RenderParticleEmitter::Mode mode /*= Mode::CONTINUOUS*/) - : AnimationModel(geometry) + : AnimationModel(geometry), + m_stopWatch(std::make_unique<StopWatch>()), m_time(time), m_emitTime(m_time), m_mode(mode) { this->setGeometry(geometry); - m_time = time; - m_emitTime = m_time; - m_mode = mode; - RenderParticleKeyFrame startFrame; startFrame.m_color = Color::White; startFrame.m_time = 0.0f; @@ -165,11 +163,11 @@ RenderParticleEmitter::update() if (!m_started) { - m_stopWatch.start(); + m_stopWatch->start(); m_started = true; } - auto time = m_stopWatch.getTimeElapsed(); + auto time = m_stopWatch->getTimeElapsed(); float dt = (float)(time - m_lastUpdateTime); m_lastUpdateTime = time; diff --git a/Source/Animation/Particles/imstkRenderParticleEmitter.h b/Source/Animation/Particles/imstkRenderParticleEmitter.h index 996e5c470970d09cf2278350450fbd23bdfe321e..33b789ea1c62d845969092ee61152759939f9dc7 100644 --- a/Source/Animation/Particles/imstkRenderParticleEmitter.h +++ b/Source/Animation/Particles/imstkRenderParticleEmitter.h @@ -23,13 +23,12 @@ #include "imstkMath.h" #include "imstkAnimationModel.h" -#include "imstkRenderParticles.h" -#include "imstkTimer.h" #include "imstkColor.h" namespace imstk { -//struct Color; +struct RenderParticle; +class StopWatch; /// /// \struct RenderParticleKeyFrame @@ -191,7 +190,7 @@ protected: float m_time; ///< total time for particle system float m_emitTime; - StopWatch m_stopWatch; + std::unique_ptr<StopWatch> m_stopWatch; double m_lastUpdateTime = 0.0; bool m_started = false; diff --git a/Source/CollisionDetection/CollisionData/imstkCollisionData.h b/Source/CollisionDetection/CollisionData/imstkCollisionData.h index 1ce677afb68837a364462647bc7c513bcb18d27a..8e49cd85a385f6fb3063e58899a5d878d6bec669 100644 --- a/Source/CollisionDetection/CollisionData/imstkCollisionData.h +++ b/Source/CollisionDetection/CollisionData/imstkCollisionData.h @@ -21,13 +21,12 @@ #pragma once -#include <array> -#include <algorithm> - -#include "imstkMath.h" #include "imstkLogger.h" +#include "imstkMath.h" #include "imstkParallelUtils.h" +#include <array> + namespace imstk { template<class DataElement> @@ -111,6 +110,7 @@ struct PositionDirectionCollisionDataElement Vec3d posA; Vec3d posB; Vec3d dirAtoB; + uint32_t nodeIdx; double penetrationDepth; }; class PositionDirectionCollisionData : public CollisionDataBase<PositionDirectionCollisionDataElement> diff --git a/Source/CollisionDetection/CollisionDetection/imstkBidirectionalPlaneToSphereCD.h b/Source/CollisionDetection/CollisionDetection/imstkBidirectionalPlaneToSphereCD.h index 7a8460f22a83b7bf7fe71617de3db8f68d09b39c..50063ed05f0474e8f80760d9ee1192bc507e571a 100644 --- a/Source/CollisionDetection/CollisionDetection/imstkBidirectionalPlaneToSphereCD.h +++ b/Source/CollisionDetection/CollisionDetection/imstkBidirectionalPlaneToSphereCD.h @@ -27,7 +27,6 @@ namespace imstk { class Plane; class Sphere; -class Geometry; struct CollisionData; /// diff --git a/Source/CollisionDetection/CollisionDetection/imstkCollisionDetection.cpp b/Source/CollisionDetection/CollisionDetection/imstkCollisionDetection.cpp index f6999298191a1c413775e78ab8eb9f8504a16493..a29e86c6f131368b1880e0b6fbc7d4aed660ef72 100644 --- a/Source/CollisionDetection/CollisionDetection/imstkCollisionDetection.cpp +++ b/Source/CollisionDetection/CollisionDetection/imstkCollisionDetection.cpp @@ -21,10 +21,9 @@ #include "imstkCollisionDetection.h" #include "imstkCollisionData.h" -#include "imstkTaskNode.h" -#include "imstkLogger.h" #include "imstkOctreeBasedCD.h" #include "imstkSurfaceMesh.h" +#include "imstkTaskNode.h" namespace imstk { diff --git a/Source/CollisionDetection/CollisionDetection/imstkCollisionDetection.h b/Source/CollisionDetection/CollisionDetection/imstkCollisionDetection.h index a1be7c2f1761c7a040545f7c88f63c60ec538426..b2c17c752859db5e56575a17a5e023141b5bfc5e 100644 --- a/Source/CollisionDetection/CollisionDetection/imstkCollisionDetection.h +++ b/Source/CollisionDetection/CollisionDetection/imstkCollisionDetection.h @@ -46,12 +46,13 @@ public: /// enum class Type { - // Points to objects + // Points to analytical geometry PointSetToSphere, PointSetToPlane, PointSetToCapsule, PointSetToSpherePicking, PointSetToSurfaceMesh, + PointSetToImplicit, // Mesh to mesh (mesh to analytical object = mesh vertices to analytical object) SurfaceMeshToSurfaceMesh, @@ -65,9 +66,6 @@ public: SphereToCylinder, SphereToSphere, - // Image based CD - SignedDistanceField, - Custom }; diff --git a/Source/CollisionDetection/CollisionDetection/imstkCollisionUtils.h b/Source/CollisionDetection/CollisionDetection/imstkCollisionUtils.h index 72652233599915cc63fccaf5e61fd03c4c2ae550..566a20a645b5c92ef70aea744db66ee307ffb7e7 100644 --- a/Source/CollisionDetection/CollisionDetection/imstkCollisionUtils.h +++ b/Source/CollisionDetection/CollisionDetection/imstkCollisionUtils.h @@ -22,6 +22,7 @@ #pragma once #include "imstkMath.h" + #include <algorithm> namespace imstk diff --git a/Source/CollisionDetection/CollisionDetection/imstkImplicitGeometryToPointSetCD.cpp b/Source/CollisionDetection/CollisionDetection/imstkImplicitGeometryToPointSetCD.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e063b5404c85a2d61244a38b109b10f548970346 --- /dev/null +++ b/Source/CollisionDetection/CollisionDetection/imstkImplicitGeometryToPointSetCD.cpp @@ -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. + +=========================================================================*/ + +#include "imstkImplicitGeometryToPointSetCD.h" +#include "imstkCollisionData.h" +#include "imstkImplicitGeometry.h" +#include "imstkMath.h" +#include "imstkPointSet.h" + +#include "imstkSignedDistanceField.h" +#include "imstkImageData.h" + +namespace imstk +{ +ImplicitGeometryToPointSetCD::ImplicitGeometryToPointSetCD(std::shared_ptr<ImplicitGeometry> implicitGeomA, + std::shared_ptr<PointSet> pointSetB, + std::shared_ptr<CollisionData> colData) : + CollisionDetection(CollisionDetection::Type::PointSetToImplicit, colData), + m_implicitGeomA(implicitGeomA), + m_pointSetB(pointSetB) +{ + centralGrad.setFunction(m_implicitGeomA); + if (m_implicitGeomA->getType() == Geometry::Type::SignedDistanceField) + { + centralGrad.setDx(std::dynamic_pointer_cast<SignedDistanceField>(m_implicitGeomA)->getImage()->getSpacing()); + } +} + +void +ImplicitGeometryToPointSetCD::computeCollisionData() +{ + m_colData->clearAll(); + + ParallelUtils::parallelFor(m_pointSetB->getVertexPositions().size(), + [&](const size_t idx) + { + const Vec3d& pt = m_pointSetB->getVertexPosition(idx); + + const double signedDistance = m_implicitGeomA->getFunctionValue(pt); + if (signedDistance < 0.0) + { + PositionDirectionCollisionDataElement elem; + elem.dirAtoB = -centralGrad(pt).normalized(); // Contact Normal + elem.nodeIdx = static_cast<uint32_t>(idx); + elem.penetrationDepth = std::abs(signedDistance); + elem.posB = pt; + m_colData->PDColData.safeAppend(elem); + } + }); +} +} \ No newline at end of file diff --git a/Source/CollisionDetection/CollisionDetection/imstkImplicitGeometryToPointSetCD.h b/Source/CollisionDetection/CollisionDetection/imstkImplicitGeometryToPointSetCD.h new file mode 100644 index 0000000000000000000000000000000000000000..2f35b03636607a052b9bdf2ff993f01ff9065f85 --- /dev/null +++ b/Source/CollisionDetection/CollisionDetection/imstkImplicitGeometryToPointSetCD.h @@ -0,0 +1,61 @@ +/*========================================================================= + +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 "imstkCollisionDetection.h" +#include "imstkImplicitFunctionFiniteDifferenceFunctor.h" + +namespace imstk +{ +class ImplicitGeometry; +class PointSet; +struct CollisionData; + +/// +/// \class ImplicitGeometryToPointSetCD +/// +/// \brief ImplicitGeometry to PointSet collision detection. +/// +class ImplicitGeometryToPointSetCD : public CollisionDetection +{ +public: + /// + /// \brief + /// \param ImplicitGeometry + /// \param PointSet to test collision with + /// \param CollisionData to write too + /// + ImplicitGeometryToPointSetCD(std::shared_ptr<ImplicitGeometry> implicitGeomA, + std::shared_ptr<PointSet> pointSetB, + std::shared_ptr<CollisionData> colData); + + /// + /// \brief Detect collision and compute collision data + /// + void computeCollisionData() override; + +private: + std::shared_ptr<ImplicitGeometry> m_implicitGeomA; + std::shared_ptr<PointSet> m_pointSetB; + ImplicitFunctionCentralGradient centralGrad; +}; +} \ No newline at end of file diff --git a/Source/CollisionDetection/CollisionDetection/imstkMeshToMeshBruteForceCD.cpp b/Source/CollisionDetection/CollisionDetection/imstkMeshToMeshBruteForceCD.cpp index a59e0ab21367088465ab2bdec6a256b05f68c373..49901d296be6567bf1b6da08f3f063fe3939df36 100644 --- a/Source/CollisionDetection/CollisionDetection/imstkMeshToMeshBruteForceCD.cpp +++ b/Source/CollisionDetection/CollisionDetection/imstkMeshToMeshBruteForceCD.cpp @@ -20,17 +20,10 @@ =========================================================================*/ #include "imstkMeshToMeshBruteForceCD.h" - -//#include "imstkCollidingObject.h" #include "imstkCollisionData.h" -#include "imstkSurfaceMesh.h" -#include "imstkPointSet.h" -#include "imstkLineMesh.h" -#include "imstkGeometry.h" -//#include "imstkColor.h" #include "imstkCollisionUtils.h" - -#include <g3log/g3log.hpp> +#include "imstkLineMesh.h" +#include "imstkSurfaceMesh.h" namespace imstk { diff --git a/Source/CollisionDetection/CollisionDetection/imstkNarrowPhaseCD.cpp b/Source/CollisionDetection/CollisionDetection/imstkNarrowPhaseCD.cpp index f9ca5f77282f58085536a668014ee25c940d321b..d6fe6dcea7feaf8d93ba91602ea39a5cc0f0ddd7 100644 --- a/Source/CollisionDetection/CollisionDetection/imstkNarrowPhaseCD.cpp +++ b/Source/CollisionDetection/CollisionDetection/imstkNarrowPhaseCD.cpp @@ -20,14 +20,12 @@ =========================================================================*/ #include "imstkNarrowPhaseCD.h" -#include "imstkCollisionUtils.h" - -#include "imstkLogger.h" +#include "imstkCapsule.h" #include "imstkCollisionData.h" +#include "imstkCollisionUtils.h" +#include "imstkCylinder.h" #include "imstkPlane.h" #include "imstkSphere.h" -#include "imstkCapsule.h" -#include "imstkCylinder.h" #include "imstkSurfaceMesh.h" namespace imstk @@ -80,9 +78,12 @@ bidirectionalPlaneToSphere(Plane* const planeA, Sphere* const sphereB, Vec3d sphereBColPt = sphereBPos - dirAToB * r; // Set collisionData - colData->PDColData.safeAppend({ planeAColPt, - sphereBColPt, - dirAToB, penetrationDepth }); + PositionDirectionCollisionDataElement elem; + elem.dirAtoB = dirAToB; + elem.penetrationDepth = penetrationDepth; + elem.posA = planeAColPt; + elem.posB = sphereBColPt; + colData->PDColData.safeAppend(elem); } void @@ -124,9 +125,12 @@ unidirectionalPlaneToSphere(Plane* const plane, Sphere* const sphere, Vec3d sphereBColPt = sphereBPos - n * r; // Set collisionData - colData->PDColData.safeAppend({ planeAColPt, - sphereBColPt, - n, penetrationDepth }); + PositionDirectionCollisionDataElement elem; + elem.dirAtoB = n; + elem.penetrationDepth = penetrationDepth; + elem.posA = planeAColPt; + elem.posB = sphereBColPt; + colData->PDColData.safeAppend(elem); } void @@ -171,9 +175,12 @@ sphereToCylinder(Sphere* const sphere, Cylinder* const cylinder, n * rCylinder; // Set collisionData - colData->PDColData.safeAppend({ sphereColPt, - cylinderColPt, - n, penetrationDepth }); + PositionDirectionCollisionDataElement elem; + elem.dirAtoB = n; + elem.penetrationDepth = penetrationDepth; + elem.posA = sphereColPt; + elem.posB = cylinderColPt; + colData->PDColData.safeAppend(elem); } void @@ -218,9 +225,12 @@ sphereToSphere(Sphere* const sphereA, Sphere* const sphereB, Vec3d sphereBColPt = sphereBPos - dirAToB * rB; // Set collisionData - colData->PDColData.safeAppend({ sphereAColPt, - sphereBColPt, - dirAToB, penetrationDepth }); + PositionDirectionCollisionDataElement elem; + elem.dirAtoB = dirAToB; + elem.penetrationDepth = penetrationDepth; + elem.posA = sphereAColPt; + elem.posB = sphereBColPt; + colData->PDColData.safeAppend(elem); } void diff --git a/Source/CollisionDetection/CollisionDetection/imstkNarrowPhaseCD.h b/Source/CollisionDetection/CollisionDetection/imstkNarrowPhaseCD.h index bcb6b7c33575bd05968c8e07ec87b6448662dfb7..d3f937d6c58734bf4d8a8fa902346321042b3024 100644 --- a/Source/CollisionDetection/CollisionDetection/imstkNarrowPhaseCD.h +++ b/Source/CollisionDetection/CollisionDetection/imstkNarrowPhaseCD.h @@ -21,10 +21,10 @@ #pragma once -#include <memory> - #include "imstkMath.h" +#include <memory> + namespace imstk { struct CollisionData; diff --git a/Source/CollisionDetection/CollisionDetection/imstkOctreeBasedCD.cpp b/Source/CollisionDetection/CollisionDetection/imstkOctreeBasedCD.cpp index f290aec5f38e33d6bdf7dd25e88d5fc6f98d652f..cf9da3d9ededae4f4771c34dff4641bcdeb749d5 100644 --- a/Source/CollisionDetection/CollisionDetection/imstkOctreeBasedCD.cpp +++ b/Source/CollisionDetection/CollisionDetection/imstkOctreeBasedCD.cpp @@ -20,15 +20,10 @@ =========================================================================*/ #include "imstkOctreeBasedCD.h" - -#include "imstkGeometry.h" -#include "imstkPointSet.h" -#include "imstkSurfaceMesh.h" - -// Collision detection headers -#include "imstkNarrowPhaseCD.h" #include "imstkCollisionData.h" #include "imstkCollisionUtils.h" +#include "imstkGeometry.h" +#include "imstkNarrowPhaseCD.h" namespace imstk { diff --git a/Source/CollisionDetection/CollisionDetection/imstkOctreeBasedCD.h b/Source/CollisionDetection/CollisionDetection/imstkOctreeBasedCD.h index 01778ee68451ed2a877b9e80313bce5d6931eecb..f39ab1b517b71330e8711314e053d33192fb5a16 100644 --- a/Source/CollisionDetection/CollisionDetection/imstkOctreeBasedCD.h +++ b/Source/CollisionDetection/CollisionDetection/imstkOctreeBasedCD.h @@ -71,7 +71,7 @@ public: /// void addCollisionPair(const std::shared_ptr<Geometry>& geom1, const std::shared_ptr<Geometry>& geom2, const CollisionDetection::Type collisionType, - const std::shared_ptr<CollisionData>& collisionData = std::make_shared<CollisionData>()); + const std::shared_ptr<CollisionData>& collisionData); /// /// \brief Get pairs of geometries from the added collision pairs diff --git a/Source/CollisionDetection/CollisionDetection/imstkPointSetToCapsuleCD.cpp b/Source/CollisionDetection/CollisionDetection/imstkPointSetToCapsuleCD.cpp index 800d90bf313021274ccdb584277760ba44ebdacc..d2ae737d88e43163cb73fc6c686c41e94a5c5ca0 100644 --- a/Source/CollisionDetection/CollisionDetection/imstkPointSetToCapsuleCD.cpp +++ b/Source/CollisionDetection/CollisionDetection/imstkPointSetToCapsuleCD.cpp @@ -20,9 +20,8 @@ =========================================================================*/ #include "imstkPointSetToCapsuleCD.h" -#include "imstkNarrowPhaseCD.h" #include "imstkCollisionData.h" -#include "imstkParallelUtils.h" +#include "imstkNarrowPhaseCD.h" #include "imstkPointSet.h" namespace imstk diff --git a/Source/CollisionDetection/CollisionDetection/imstkPointSetToPlaneCD.cpp b/Source/CollisionDetection/CollisionDetection/imstkPointSetToPlaneCD.cpp index 9d6ca6638409550f16f41989d51037d326bd26e6..f27e80cafc974ea1b02ac384589c3868dfe4298e 100644 --- a/Source/CollisionDetection/CollisionDetection/imstkPointSetToPlaneCD.cpp +++ b/Source/CollisionDetection/CollisionDetection/imstkPointSetToPlaneCD.cpp @@ -20,9 +20,8 @@ =========================================================================*/ #include "imstkPointSetToPlaneCD.h" -#include "imstkNarrowPhaseCD.h" #include "imstkCollisionData.h" -#include "imstkParallelUtils.h" +#include "imstkNarrowPhaseCD.h" #include "imstkPointSet.h" namespace imstk diff --git a/Source/CollisionDetection/CollisionDetection/imstkPointSetToSphereCD.cpp b/Source/CollisionDetection/CollisionDetection/imstkPointSetToSphereCD.cpp index 6365dbd41fa06de876b2a17ed5342e0a68d45a01..3268060339e61c7c2306143436a48cdb807bbdf6 100644 --- a/Source/CollisionDetection/CollisionDetection/imstkPointSetToSphereCD.cpp +++ b/Source/CollisionDetection/CollisionDetection/imstkPointSetToSphereCD.cpp @@ -20,9 +20,8 @@ =========================================================================*/ #include "imstkPointSetToSphereCD.h" -#include "imstkNarrowPhaseCD.h" #include "imstkCollisionData.h" -#include "imstkParallelUtils.h" +#include "imstkNarrowPhaseCD.h" #include "imstkPointSet.h" namespace imstk diff --git a/Source/CollisionDetection/CollisionDetection/imstkPointSetToSurfaceMeshCD.cpp b/Source/CollisionDetection/CollisionDetection/imstkPointSetToSurfaceMeshCD.cpp index 81569e9d8c08569f472fa2ccbc5fc116b4a61cc7..60631ce7706c0465ea9ed87840fd0caefa2aa75e 100644 --- a/Source/CollisionDetection/CollisionDetection/imstkPointSetToSurfaceMeshCD.cpp +++ b/Source/CollisionDetection/CollisionDetection/imstkPointSetToSurfaceMeshCD.cpp @@ -20,10 +20,8 @@ =========================================================================*/ #include "imstkPointSetToSurfaceMeshCD.h" -#include "imstkCollisionData.h" -#include "imstkPointSet.h" -#include "imstkSurfaceMesh.h" #include "imstkOctreeBasedCD.h" +#include "imstkSurfaceMesh.h" namespace imstk { diff --git a/Source/CollisionDetection/CollisionDetection/imstkSphereToCylinderCD.cpp b/Source/CollisionDetection/CollisionDetection/imstkSphereToCylinderCD.cpp index 7a741535575383e04b251abf8e4890a643f81d56..d854828691d127bf440125fe0d03d64cde001259 100644 --- a/Source/CollisionDetection/CollisionDetection/imstkSphereToCylinderCD.cpp +++ b/Source/CollisionDetection/CollisionDetection/imstkSphereToCylinderCD.cpp @@ -20,8 +20,8 @@ =========================================================================*/ #include "imstkSphereToCylinderCD.h" -#include "imstkNarrowPhaseCD.h" #include "imstkCollisionData.h" +#include "imstkNarrowPhaseCD.h" namespace imstk { diff --git a/Source/CollisionDetection/CollisionDetection/imstkSphereToSphereCD.cpp b/Source/CollisionDetection/CollisionDetection/imstkSphereToSphereCD.cpp index 027def93ffc03b59b9cfea645ac86a2c3ccaff2f..d446647d5a7c60a38b4c985a40523503d0afa72e 100644 --- a/Source/CollisionDetection/CollisionDetection/imstkSphereToSphereCD.cpp +++ b/Source/CollisionDetection/CollisionDetection/imstkSphereToSphereCD.cpp @@ -20,8 +20,8 @@ =========================================================================*/ #include "imstkSphereToSphereCD.h" -#include "imstkNarrowPhaseCD.h" #include "imstkCollisionData.h" +#include "imstkNarrowPhaseCD.h" namespace imstk { diff --git a/Source/CollisionDetection/CollisionDetection/imstkSurfaceMeshToSurfaceMeshCCD.cpp b/Source/CollisionDetection/CollisionDetection/imstkSurfaceMeshToSurfaceMeshCCD.cpp index 49ed12f5936fbb85171110419d46c7802de0d221..abf16ea123ab45427b8cf42a9bb009590b5143e1 100644 --- a/Source/CollisionDetection/CollisionDetection/imstkSurfaceMeshToSurfaceMeshCCD.cpp +++ b/Source/CollisionDetection/CollisionDetection/imstkSurfaceMeshToSurfaceMeshCCD.cpp @@ -20,9 +20,9 @@ =========================================================================*/ #include "imstkSurfaceMeshToSurfaceMeshCCD.h" +#include "DeformModel.h" #include "imstkCollisionData.h" #include "imstkSurfaceMesh.h" -#include "DeformModel.h" namespace imstk { diff --git a/Source/CollisionDetection/CollisionDetection/imstkSurfaceMeshToSurfaceMeshCD.cpp b/Source/CollisionDetection/CollisionDetection/imstkSurfaceMeshToSurfaceMeshCD.cpp index 7eebc044aef0b927637a3d5f09d19cc22b415dcc..da33e3a9f77354169f335825c3336dbd6c8843c1 100644 --- a/Source/CollisionDetection/CollisionDetection/imstkSurfaceMeshToSurfaceMeshCD.cpp +++ b/Source/CollisionDetection/CollisionDetection/imstkSurfaceMeshToSurfaceMeshCD.cpp @@ -20,10 +20,8 @@ =========================================================================*/ #include "imstkSurfaceMeshToSurfaceMeshCD.h" -#include "imstkNarrowPhaseCD.h" -#include "imstkCollisionData.h" -#include "imstkSurfaceMesh.h" #include "imstkOctreeBasedCD.h" +#include "imstkSurfaceMesh.h" namespace imstk { diff --git a/Source/CollisionDetection/CollisionDetection/imstkTetraToTetraCD.cpp b/Source/CollisionDetection/CollisionDetection/imstkTetraToTetraCD.cpp index afb078990007d1dccbb296f60d451370e703ba47..47de40b98f69b6d37f5d0055a60776f151eaa312 100644 --- a/Source/CollisionDetection/CollisionDetection/imstkTetraToTetraCD.cpp +++ b/Source/CollisionDetection/CollisionDetection/imstkTetraToTetraCD.cpp @@ -21,13 +21,8 @@ #include "imstkTetraToTetraCD.h" #include "imstkCollisionData.h" -#include "imstkMath.h" -#include "imstkParallelUtils.h" -#include "imstkSurfaceMesh.h" #include "imstkTetrahedralMesh.h" -//#include "DeformModel.h" - namespace imstk { TetraToTetraCD::TetraToTetraCD(std::shared_ptr<TetrahedralMesh> meshA, diff --git a/Source/CollisionDetection/CollisionDetection/imstkTetraToTetraCD.h b/Source/CollisionDetection/CollisionDetection/imstkTetraToTetraCD.h index 9403bdb53d0a9fe1ede5de4ca2584345057a5e92..ff20c99589b1f99ab8188974e166295e80e2a5fc 100644 --- a/Source/CollisionDetection/CollisionDetection/imstkTetraToTetraCD.h +++ b/Source/CollisionDetection/CollisionDetection/imstkTetraToTetraCD.h @@ -21,7 +21,6 @@ #pragma once -// imstk #include "imstkCollisionDetection.h" #include "imstkSpatialHashTableSeparateChaining.h" diff --git a/Source/CollisionDetection/CollisionDetection/imstkUnidirectionalPlaneToSphereCD.cpp b/Source/CollisionDetection/CollisionDetection/imstkUnidirectionalPlaneToSphereCD.cpp index 05c82062aa4b25b55dde8db3fe729cf3cafb4548..44c7984e6427c97d6611f5ec4939d7a9ec267413 100644 --- a/Source/CollisionDetection/CollisionDetection/imstkUnidirectionalPlaneToSphereCD.cpp +++ b/Source/CollisionDetection/CollisionDetection/imstkUnidirectionalPlaneToSphereCD.cpp @@ -20,8 +20,8 @@ =========================================================================*/ #include "imstkUnidirectionalPlaneToSphereCD.h" -#include "imstkNarrowPhaseCD.h" #include "imstkCollisionData.h" +#include "imstkNarrowPhaseCD.h" namespace imstk { diff --git a/Source/CollisionDetection/Testing/imstkOctreeBasedCDTest.cpp b/Source/CollisionDetection/Testing/imstkOctreeBasedCDTest.cpp index 302a489fd75ca8c2cc41c6b1c6c6dd1bd64f32c4..fb8174927b1c88c413d52e03c3e899e4d7b8e47a 100644 --- a/Source/CollisionDetection/Testing/imstkOctreeBasedCDTest.cpp +++ b/Source/CollisionDetection/Testing/imstkOctreeBasedCDTest.cpp @@ -19,22 +19,16 @@ =========================================================================*/ -#include "gtest/gtest.h" -#include "gmock/gmock.h" +#include <gtest/gtest.h> -#include "imstkMath.h" -#include "imstkSphere.h" -#include "imstkPointSet.h" -#include "imstkSurfaceMesh.h" #include "imstkCollisionData.h" #include "imstkNarrowPhaseCD.h" - #include "imstkOctreeBasedCD.h" #include "imstkPointSetToSurfaceMeshCD.h" +#include "imstkSphere.h" +#include "imstkSurfaceMesh.h" #include "imstkSurfaceMeshToSurfaceMeshCD.h" -#include <iostream> -#include <unordered_set> #include <unordered_map> using namespace imstk; @@ -230,7 +224,7 @@ public: } // Detect penetration using octree - m_OctreeCD->addCollisionPair(pointset, mesh, CollisionDetection::Type::PointSetToSurfaceMesh); + m_OctreeCD->addCollisionPair(pointset, mesh, CollisionDetection::Type::PointSetToSurfaceMesh, std::make_shared<CollisionData>()); m_OctreeCD->detectCollision(); const auto collisionData = m_OctreeCD->getCollisionPairData(pointset->getGlobalIndex(), mesh->getGlobalIndex()); #ifdef PRINT_DEBUG @@ -335,7 +329,7 @@ public: } // Detect penetration using octree - m_OctreeCD->addCollisionPair(pointset, sphere, CollisionDetection::Type::PointSetToSphere); + m_OctreeCD->addCollisionPair(pointset, sphere, CollisionDetection::Type::PointSetToSphere, std::make_shared<CollisionData>()); m_OctreeCD->detectCollision(); const auto collisionData = m_OctreeCD->getCollisionPairData(pointset->getGlobalIndex(), sphere->getGlobalIndex()); #ifdef PRINT_DEBUG @@ -393,7 +387,7 @@ public: } // Detect collision using octree - m_OctreeCD->addCollisionPair(mesh, box, CollisionDetection::Type::SurfaceMeshToSurfaceMesh); + m_OctreeCD->addCollisionPair(mesh, box, CollisionDetection::Type::SurfaceMeshToSurfaceMesh, std::make_shared<CollisionData>()); m_OctreeCD->detectCollision(); collisionData = m_OctreeCD->getCollisionPairData(mesh->getGlobalIndex(), box->getGlobalIndex()); #ifdef PRINT_DEBUG diff --git a/Source/CollisionDetection/Testing/imstkTetraToTetraCDTest.cpp b/Source/CollisionDetection/Testing/imstkTetraToTetraCDTest.cpp index 49536eb89ffde4edffe624c2ef54f9d191d881be..43df34ecb838e4f9436c762b584ac6f2f51e7003 100644 --- a/Source/CollisionDetection/Testing/imstkTetraToTetraCDTest.cpp +++ b/Source/CollisionDetection/Testing/imstkTetraToTetraCDTest.cpp @@ -20,9 +20,6 @@ =========================================================================*/ #include "gtest/gtest.h" -#include "gmock/gmock.h" - -#include <memory> #include "imstkCollisionData.h" #include "imstkMeshIO.h" diff --git a/Source/CollisionDetection/imstkCDObjectFactory.cpp b/Source/CollisionDetection/imstkCDObjectFactory.cpp index 668990d220005b1e0974f328ba32820441ed2c1e..1697264d87555976defde20676af24c5a45e35a3 100644 --- a/Source/CollisionDetection/imstkCDObjectFactory.cpp +++ b/Source/CollisionDetection/imstkCDObjectFactory.cpp @@ -21,14 +21,13 @@ limitations under the License. #include "imstkCDObjectFactory.h" #include "imstkCollisionData.h" -#include "imstkOctreeBasedCD.h" // Points to objects #include "imstkPointSetToCapsuleCD.h" #include "imstkPointSetToPlaneCD.h" #include "imstkPointSetToSphereCD.h" -#include "imstkPointSetToSpherePickingCD.h" #include "imstkPointSetToSurfaceMeshCD.h" +#include "imstkImplicitGeometryToPointSetCD.h" // Mesh to mesh #include "imstkMeshToMeshBruteForceCD.h" @@ -45,125 +44,165 @@ limitations under the License. // Geometry #include "imstkCapsule.h" #include "imstkCylinder.h" -#include "imstkImageData.h" +#include "imstkImplicitGeometry.h" #include "imstkPlane.h" #include "imstkSphere.h" #include "imstkSurfaceMesh.h" #include "imstkTetrahedralMesh.h" -#define IMSTK_CHECK_FOR_VALID_GEOMETRIES(obj1, obj2) \ - LOG_IF(FATAL, (obj1 == nullptr || obj2 == nullptr)) << \ - "CollisionDetection::makeCollisionDetectionObject() error: " << \ - "Invalid object geometries were provided for the given collision detection type.\n" << \ - " Line: " << __LINE__ << ", File: " << __FILE__; +#define IMSTK_CHECK_FOR_VALID_GEOMETRIES(obj1, obj2, Type1, Type2) \ + checkValidGeometry<Type1, Type2>(obj1, obj2, #Type1, #Type2); namespace imstk { +template<typename T1, typename T2> +void +checkValidGeometry(std::shared_ptr<Geometry> geom1, std::shared_ptr<Geometry> geom2, std::string t1TypeName, std::string t2TypeName) +{ + std::string errorMsg = "Invalid object geometries were provided for the collision detection type.\n"; + bool fail = false; + if (std::dynamic_pointer_cast<T1>(geom1) == nullptr) + { + errorMsg += "Geometry 1 expected " + t1TypeName + " but got " + geom1->getTypeName() + ".\n"; + fail = true; + } + if (std::dynamic_pointer_cast<T2>(geom2) == nullptr) + { + errorMsg += "Geometry 2 expected " + t2TypeName + " but got " + geom2->getTypeName() + ".\n"; + fail = true; + } + + if (fail) + { + LOG(FATAL) << errorMsg; + } +} + std::shared_ptr<CollisionDetection> makeCollisionDetectionObject(const CollisionDetection::Type type, std::shared_ptr<Geometry> collidingGeometryA, std::shared_ptr<Geometry> collidingGeometryB, std::shared_ptr<CollisionData> colData) { + if (collidingGeometryA == nullptr) + { + LOG(FATAL) << "Collision Geometry A nullptr"; + } + if (collidingGeometryB == nullptr) + { + LOG(FATAL) << "Collision Geometry B nullptr"; + } + switch (type) { // Points to objects case CollisionDetection::Type::PointSetToSphere: { + IMSTK_CHECK_FOR_VALID_GEOMETRIES(collidingGeometryA, collidingGeometryB, PointSet, Sphere); + auto pointset = std::dynamic_pointer_cast<PointSet>(collidingGeometryA); auto sphere = std::dynamic_pointer_cast<Sphere>(collidingGeometryB); - IMSTK_CHECK_FOR_VALID_GEOMETRIES(pointset, sphere) return std::make_shared<PointSetToSphereCD>(pointset, sphere, colData); } case CollisionDetection::Type::PointSetToPlane: { + IMSTK_CHECK_FOR_VALID_GEOMETRIES(collidingGeometryA, collidingGeometryB, PointSet, Sphere); + auto pointset = std::dynamic_pointer_cast<PointSet>(collidingGeometryA); auto plane = std::dynamic_pointer_cast<Plane>(collidingGeometryB); - IMSTK_CHECK_FOR_VALID_GEOMETRIES(pointset, plane) return std::make_shared<PointSetToPlaneCD>(pointset, plane, colData); } case CollisionDetection::Type::PointSetToCapsule: { + IMSTK_CHECK_FOR_VALID_GEOMETRIES(collidingGeometryA, collidingGeometryB, PointSet, Capsule); + auto pointset = std::dynamic_pointer_cast<PointSet>(collidingGeometryA); auto capsule = std::dynamic_pointer_cast<Capsule>(collidingGeometryB); - IMSTK_CHECK_FOR_VALID_GEOMETRIES(pointset, capsule) return std::make_shared<PointSetToCapsuleCD>(pointset, capsule, colData); } -#if 0 - case CollisionDetection::ype::PointSetToSpherePicking: - { - auto pointset = std::dynamic_pointer_cast<PointSet>(objA->getCollidingGeometry()); - auto sphere = std::dynamic_pointer_cast<Sphere>(objB->getCollidingGeometry()); - IMSTK_CHECK_FOR_VALID_GEOMETRIES(pointset, sphere) - return std::make_shared<PointSetToSpherePickingCD>(pointset, sphere, colData); - } -#endif case CollisionDetection::Type::PointSetToSurfaceMesh: { + IMSTK_CHECK_FOR_VALID_GEOMETRIES(collidingGeometryA, collidingGeometryB, PointSet, SurfaceMesh); + auto pointset = std::dynamic_pointer_cast<PointSet>(collidingGeometryA); auto triMesh = std::dynamic_pointer_cast<SurfaceMesh>(collidingGeometryB); - IMSTK_CHECK_FOR_VALID_GEOMETRIES(pointset, triMesh) CollisionDetection::addCollisionPairToOctree(collidingGeometryA, collidingGeometryB, type, colData); return std::make_shared<PointSetToSurfaceMeshCD>(pointset, triMesh, colData); } + case CollisionDetection::Type::PointSetToImplicit: + { + IMSTK_CHECK_FOR_VALID_GEOMETRIES(collidingGeometryA, collidingGeometryB, PointSet, ImplicitGeometry); + + auto pointSet = std::dynamic_pointer_cast<PointSet>(collidingGeometryA); + auto implicitGeom = std::dynamic_pointer_cast<ImplicitGeometry>(collidingGeometryB); + return std::make_shared<ImplicitGeometryToPointSetCD>(implicitGeom, pointSet, colData); + } // Mesh to mesh case CollisionDetection::Type::SurfaceMeshToSurfaceMesh: { + IMSTK_CHECK_FOR_VALID_GEOMETRIES(collidingGeometryA, collidingGeometryB, SurfaceMesh, SurfaceMesh); + auto meshA = std::dynamic_pointer_cast<SurfaceMesh>(collidingGeometryA); auto meshB = std::dynamic_pointer_cast<SurfaceMesh>(collidingGeometryB); - IMSTK_CHECK_FOR_VALID_GEOMETRIES(meshA, meshB) CollisionDetection::addCollisionPairToOctree(collidingGeometryA, collidingGeometryB, type, colData); return std::make_shared<SurfaceMeshToSurfaceMeshCD>(meshA, meshB, colData); } case CollisionDetection::Type::SurfaceMeshToSurfaceMeshCCD: { + IMSTK_CHECK_FOR_VALID_GEOMETRIES(collidingGeometryA, collidingGeometryB, SurfaceMesh, SurfaceMesh); + auto meshA = std::dynamic_pointer_cast<SurfaceMesh>(collidingGeometryA); auto meshB = std::dynamic_pointer_cast<SurfaceMesh>(collidingGeometryB); - IMSTK_CHECK_FOR_VALID_GEOMETRIES(meshA, meshB) return std::make_shared<SurfaceMeshToSurfaceMeshCCD>(meshA, meshB, colData); } case CollisionDetection::Type::VolumeMeshToVolumeMesh: { + IMSTK_CHECK_FOR_VALID_GEOMETRIES(collidingGeometryA, collidingGeometryB, TetrahedralMesh, TetrahedralMesh); + auto tet1 = std::dynamic_pointer_cast<TetrahedralMesh>(collidingGeometryA); auto tet2 = std::dynamic_pointer_cast<TetrahedralMesh>(collidingGeometryB); - IMSTK_CHECK_FOR_VALID_GEOMETRIES(tet1, tet2) return std::make_shared<TetraToTetraCD>(tet1, tet2, colData); } // Analytical object to analytical object case CollisionDetection::Type::UnidirectionalPlaneToSphere: { + IMSTK_CHECK_FOR_VALID_GEOMETRIES(collidingGeometryA, collidingGeometryB, Plane, Sphere); + auto plane = std::dynamic_pointer_cast<Plane>(collidingGeometryA); auto sphere = std::dynamic_pointer_cast<Sphere>(collidingGeometryB); - IMSTK_CHECK_FOR_VALID_GEOMETRIES(plane, sphere) return std::make_shared<UnidirectionalPlaneToSphereCD>(plane, sphere, colData); } case CollisionDetection::Type::BidirectionalPlaneToSphere: { + IMSTK_CHECK_FOR_VALID_GEOMETRIES(collidingGeometryA, collidingGeometryB, Plane, Sphere); + auto plane = std::dynamic_pointer_cast<Plane>(collidingGeometryA); auto sphere = std::dynamic_pointer_cast<Sphere>(collidingGeometryB); - IMSTK_CHECK_FOR_VALID_GEOMETRIES(plane, sphere) return std::make_shared<BidirectionalPlaneToSphereCD>(plane, sphere, colData); } case CollisionDetection::Type::SphereToSphere: { + IMSTK_CHECK_FOR_VALID_GEOMETRIES(collidingGeometryA, collidingGeometryB, Sphere, Sphere); + auto sphereA = std::dynamic_pointer_cast<Sphere>(collidingGeometryA); auto sphereB = std::dynamic_pointer_cast<Sphere>(collidingGeometryB); - IMSTK_CHECK_FOR_VALID_GEOMETRIES(sphereA, sphereB) return std::make_shared<SphereToSphereCD>(sphereA, sphereB, colData); } case CollisionDetection::Type::SphereToCylinder: { - auto sphere = std::dynamic_pointer_cast<Sphere>(collidingGeometryB); + IMSTK_CHECK_FOR_VALID_GEOMETRIES(collidingGeometryA, collidingGeometryB, Cylinder, Sphere); + auto cylinder = std::dynamic_pointer_cast<Cylinder>(collidingGeometryA); - IMSTK_CHECK_FOR_VALID_GEOMETRIES(sphere, cylinder) + auto sphere = std::dynamic_pointer_cast<Sphere>(collidingGeometryB); return std::make_shared<SphereToCylinderCD>(sphere, cylinder, colData); } case CollisionDetection::Type::MeshToMeshBruteForce: { + IMSTK_CHECK_FOR_VALID_GEOMETRIES(collidingGeometryA, collidingGeometryB, Geometry, SurfaceMesh); + auto meshB = std::dynamic_pointer_cast<SurfaceMesh>(collidingGeometryB); - IMSTK_CHECK_FOR_VALID_GEOMETRIES(collidingGeometryA, meshB) return std::make_shared<MeshToMeshBruteForceCD>(collidingGeometryA, meshB, colData); } default: diff --git a/Source/CollisionHandling/imstkBoneDrillingCH.cpp b/Source/CollisionHandling/imstkBoneDrillingCH.cpp index 04877d74a5ea42d9ad926e97c0b71391ec0281ab..f91f286a7238aa367a78269ba9ece57572ccd0bf 100644 --- a/Source/CollisionHandling/imstkBoneDrillingCH.cpp +++ b/Source/CollisionHandling/imstkBoneDrillingCH.cpp @@ -22,9 +22,6 @@ #include "imstkBoneDrillingCH.h" #include "imstkCollidingObject.h" #include "imstkCollisionData.h" -#include "imstkDeviceTracker.h" -#include "imstkLogger.h" -#include "imstkParallelUtils.h" #include "imstkTetrahedralMesh.h" namespace imstk diff --git a/Source/CollisionHandling/imstkBoneDrillingCH.h b/Source/CollisionHandling/imstkBoneDrillingCH.h index 476ec97701262e814ac24cd104313638e0a27f5e..baad5f7b40031a2ed95a6cd96ac33db5d5a5ec09 100644 --- a/Source/CollisionHandling/imstkBoneDrillingCH.h +++ b/Source/CollisionHandling/imstkBoneDrillingCH.h @@ -21,14 +21,12 @@ #pragma once -// imstk #include "imstkCollisionHandling.h" #include "imstkMath.h" namespace imstk { class CollidingObject; -class DeviceTracker; struct CollisionData; /// diff --git a/Source/CollisionHandling/imstkCollisionHandling.h b/Source/CollisionHandling/imstkCollisionHandling.h index ea9e05a2d77e4617a022d7ab855cb7018585c0e0..ec367199aa9ba16ed09e25de9e508a37a0084887 100644 --- a/Source/CollisionHandling/imstkCollisionHandling.h +++ b/Source/CollisionHandling/imstkCollisionHandling.h @@ -50,7 +50,9 @@ public: NodalPicking, BoneDrilling, SPH, - PBD + PBD, + RBD, + LevelSet }; /// diff --git a/Source/CollisionHandling/imstkLevelSetCH.cpp b/Source/CollisionHandling/imstkLevelSetCH.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5cb2ba1504be93862fdb3fb62a3e6d0a158294ab --- /dev/null +++ b/Source/CollisionHandling/imstkLevelSetCH.cpp @@ -0,0 +1,129 @@ +/*========================================================================= + + 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 "imstkLevelSetCH.h" +#include "imstkCollisionData.h" +#include "imstkLevelSetDeformableObject.h" +#include "imstkLevelSetModel.h" +#include "imstkImageData.h" +#include "imstkRigidObject2.h" +#include "imstkRbdConstraint.h" + +namespace imstk +{ +namespace expiremental +{ +static double gaussianKernel[3][3][3] = +{ + { + { 1.0, 2.0, 1.0 }, + { 2.0, 4.0, 2.0 }, + { 1.0, 2.0, 1.0 } + }, + { + { 2.0, 4.0, 2.0 }, + { 4.0, 8.0, 4.0 }, + { 2.0, 4.0, 2.0 } + }, + { + { 1.0, 2.0, 1.0 }, + { 2.0, 4.0, 2.0 }, + { 1.0, 2.0, 1.0 } + } +}; + +LevelSetCH::LevelSetCH(const Side& side, + const std::shared_ptr<CollisionData> colData, + std::shared_ptr<LevelSetDeformableObject> lvlSetObj, + std::shared_ptr<RigidObject2> rigidObj) : + CollisionHandling(Type::RBD, side, colData), + m_lvlSetObj(lvlSetObj), + m_rigidObj(rigidObj) +{ +} + +void +LevelSetCH::processCollisionData() +{ + std::shared_ptr<LevelSetModel> lvlSetModel = m_lvlSetObj->getLevelSetModel(); + std::shared_ptr<ImageData> grid = std::dynamic_pointer_cast<ImageData>(lvlSetModel->getModelGeometry()); + + //const Vec3i& dim = grid->getDimensions(); + const Vec3d& invSpacing = grid->getInvSpacing(); + const Vec3d& origin = grid->getOrigin(); + + //if (m_useProportionalForce) + //{ + // // Apply impulses at points of contacts + // PositionDirectionCollisionData& pdColData = m_colData->PDColData; + // for (int i = 0; i < pdColData.getSize(); i++) + // { + // const Vec3d& pos = pdColData[i].posB; + // const Vec3d& normal = pdColData[i].dirAtoB; + // const Vec3i coord = (pos - origin).cwiseProduct(invSpacing).cast<int>(); + + // const double fN = normal.dot(m_rigidObj->getRigidBody()->getForce()); + // const double S = m_velocityScaling; + + // for (int z = 0; z < 3; z++) + // { + // for (int y = 0; y < 3; y++) + // { + // for (int x = 0; x < 3; x++) + // { + // const Vec3i fCoord = coord + Vec3i(x - 1, y - 1, z - 1); + // /*float S = 0.05f * + // glm::max( + // glm::dot(-glm::normalize(computeGrad(fCoords[0], fCoords[1], imgPtr, dim, spacing)), + // glm::vec2(rigidObj->getForce())), 0.0f);*/ + // lvlSetModel->addImpulse(fCoord, S * gaussianKernel[x][y][z]); + // } + // } + // } + // } + //} + //else + { + // Apply impulses at points of contacts + PositionDirectionCollisionData& pdColData = m_colData->PDColData; + for (int i = 0; i < pdColData.getSize(); i++) + { + const Vec3d& pos = pdColData[i].posB; + //const Vec3d& normal = pdColData[i].dirAtoB; + const Vec3i coord = (pos - origin).cwiseProduct(invSpacing).cast<int>(); + const double S = m_velocityScaling; + + for (int z = 0; z < 3; z++) + { + for (int y = 0; y < 3; y++) + { + for (int x = 0; x < 3; x++) + { + const Vec3i fCoord = coord + Vec3i(x - 1, y - 1, z - 1); + lvlSetModel->addImpulse(fCoord, S * gaussianKernel[x][y][z]); + } + } + } + } + } +} +} +} \ No newline at end of file diff --git a/Source/CollisionHandling/imstkLevelSetCH.h b/Source/CollisionHandling/imstkLevelSetCH.h new file mode 100644 index 0000000000000000000000000000000000000000..32fd8327e6c2233aa7ae571aa5320f3310b7db0b --- /dev/null +++ b/Source/CollisionHandling/imstkLevelSetCH.h @@ -0,0 +1,81 @@ +/*========================================================================= + + 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 "imstkCollisionHandling.h" + +#include <vector> + +namespace imstk +{ +class LevelSetDeformableObject; +struct CollisionData; + +namespace expiremental +{ +class RigidObject2; + +/// +/// \class LevelSetCH +/// +/// \brief Applies impulses to the leveset given point direction constraints +/// propotional to the force on the rigid object +/// +class LevelSetCH : public CollisionHandling +{ +public: + LevelSetCH(const Side& side, + const std::shared_ptr<CollisionData> colData, + std::shared_ptr<LevelSetDeformableObject> lvlSetObj, + std::shared_ptr<RigidObject2> rigidObj); + + LevelSetCH() = delete; + + virtual ~LevelSetCH() override = default; + +public: + /// + /// \brief Compute forces and velocities based on collision data + /// + void processCollisionData() override; + + /// + /// \brief Set/Get Scale of the velocity used for the levelset, default 0.1 + /// + double getLevelSetVelocityScaling() const { return m_velocityScaling; } + void setLevelSetVelocityScaling(const double velocityScaling) { m_velocityScaling = velocityScaling; } + +/// +/// \brief Set/Get whether the velocity used on the levelset should be proportional to the force of the rigid body +/// along the normal of the levelset +/// +/* void setUseProportionalVelocity(const bool useProportionalForce) { m_useProportionalForce = useProportionalForce; } + bool getUseProportionalVelocity() const { return m_useProportionalForce; }*/ + +private: + std::shared_ptr<LevelSetDeformableObject> m_lvlSetObj = nullptr; + std::shared_ptr<RigidObject2> m_rigidObj = nullptr; + double m_velocityScaling = 0.002; + //bool m_useProportionalForce = false; +}; +} +} \ No newline at end of file diff --git a/Source/CollisionHandling/imstkPBDCollisionHandling.h b/Source/CollisionHandling/imstkPBDCollisionHandling.h index 3935e0db3328f3f4c93a77482f7b6fbae6a81cbe..c2e4cfe2a31a1c341ce52b64289180dbe65b89a9 100644 --- a/Source/CollisionHandling/imstkPBDCollisionHandling.h +++ b/Source/CollisionHandling/imstkPBDCollisionHandling.h @@ -21,7 +21,6 @@ #pragma once -// imstk #include "imstkCollisionHandling.h" #include <vector> diff --git a/Source/CollisionHandling/imstkPenaltyCH.cpp b/Source/CollisionHandling/imstkPenaltyCH.cpp index 1e59fa12cbc584a16712229a5f7ccadb757da249..67543fb85a1a0756bb1aeb132e32291b35118ca2 100644 --- a/Source/CollisionHandling/imstkPenaltyCH.cpp +++ b/Source/CollisionHandling/imstkPenaltyCH.cpp @@ -20,12 +20,9 @@ =========================================================================*/ #include "imstkPenaltyCH.h" -#include "imstkCollidingObject.h" #include "imstkCollisionData.h" #include "imstkFeDeformableObject.h" #include "imstkFEMDeformableBodyModel.h" -#include "imstkLogger.h" -#include "imstkParallelUtils.h" namespace imstk { diff --git a/Source/CollisionHandling/imstkPenaltyCH.h b/Source/CollisionHandling/imstkPenaltyCH.h index a252c55181779efc1abf309010fb6c30e9093c4f..60575dd49e6516f464ddc8f88c2e62ac28904229 100644 --- a/Source/CollisionHandling/imstkPenaltyCH.h +++ b/Source/CollisionHandling/imstkPenaltyCH.h @@ -21,7 +21,6 @@ #pragma once -// imstk #include "imstkCollisionHandling.h" namespace imstk diff --git a/Source/CollisionHandling/imstkPickingCH.cpp b/Source/CollisionHandling/imstkPickingCH.cpp index 92f35e96a0543d4402b602db7208c97f6ababfc1..6b25b3cd64418f9a933469e3f546f30eaa5b405b 100644 --- a/Source/CollisionHandling/imstkPickingCH.cpp +++ b/Source/CollisionHandling/imstkPickingCH.cpp @@ -20,13 +20,12 @@ limitations under the License. =========================================================================*/ #include "imstkPickingCH.h" +#include "imstkCollisionData.h" #include "imstkFeDeformableObject.h" -#include "imstkParallelUtils.h" -#include "imstkPointSet.h" #include "imstkFEMDeformableBodyModel.h" -#include "imstkTimeIntegrator.h" -#include "imstkCollisionData.h" #include "imstkLinearProjectionConstraint.h" +#include "imstkPointSet.h" +#include "imstkTimeIntegrator.h" namespace imstk { diff --git a/Source/CollisionHandling/imstkPickingCH.h b/Source/CollisionHandling/imstkPickingCH.h index 2614dde37f9ad5adc8ec3e0feb8bce1919fdbf8e..5eed9f256712672d7f63da29ce3f3c481f418a4c 100644 --- a/Source/CollisionHandling/imstkPickingCH.h +++ b/Source/CollisionHandling/imstkPickingCH.h @@ -21,7 +21,6 @@ #pragma once -// imstk #include "imstkCollisionHandling.h" #include <vector> diff --git a/Source/CollisionHandling/imstkRigidBodyCH.cpp b/Source/CollisionHandling/imstkRigidBodyCH.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e0abf8a4e8b48dad99ed6626e8111dd3baa2b386 --- /dev/null +++ b/Source/CollisionHandling/imstkRigidBodyCH.cpp @@ -0,0 +1,204 @@ +/*========================================================================= + + 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 "imstkRigidBodyCH.h" +#include "imstkCollisionData.h" +#include "imstkRbdContactConstraint.h" +#include "imstkRbdFrictionConstraint.h" +#include "imstkRigidBodyModel2.h" +#include "imstkRigidObject2.h" + +namespace imstk +{ +namespace expiremental +{ +RigidBodyCH::RigidBodyCH(const Side& side, + const std::shared_ptr<CollisionData> colData, + std::shared_ptr<RigidObject2> rbdObjectA, + std::shared_ptr<RigidObject2> rbdObjectB, + const double stiffness, + const double frictionalCoefficient) : + CollisionHandling(Type::RBD, side, colData), + m_rbdObjectA(rbdObjectA), + m_rbdObjectB(rbdObjectB), + m_stiffness(stiffness), + m_frictionalCoefficient(frictionalCoefficient), + m_useFriction(frictionalCoefficient != 0.0) +{ + if (side == Side::AB && rbdObjectA == nullptr && rbdObjectB == nullptr) + { + LOG(WARNING) << "RigidBodyCH, side AB was specified but only one object given"; + return; + } + if (side == Side::A && rbdObjectA == nullptr) + { + LOG(WARNING) << "RigidBodyCH, side A was specified but object A not given"; + return; + } + if (side == Side::B && rbdObjectB == nullptr) + { + LOG(WARNING) << "RigidBodyCH, side B was specified but object B not given"; + return; + } +} + +void +RigidBodyCH::processCollisionData() +{ + if (m_side == Side::A) + { + processA(); + } + else if (m_side == Side::B) + { + processB(); + } + else if (m_side == Side::AB) + { + std::shared_ptr<RigidBodyModel2> rbdModelA = m_rbdObjectA->getRigidBodyModel2(); + std::shared_ptr<RigidBodyModel2> rbdModelB = m_rbdObjectB->getRigidBodyModel2(); + + // If the two bodies exist in separate models, add two one way constraints + if (rbdModelA != rbdModelB) + { + if (rbdModelA != nullptr) + { + processA(); + } + if (rbdModelB != nullptr) + { + processB(); + } + } + else + { + processAB(); + } + } +} + +void +RigidBodyCH::processA() +{ + std::shared_ptr<RigidBodyModel2> rbdModelA = m_rbdObjectA->getRigidBodyModel2(); + // Generate one-way constraints + PositionDirectionCollisionData& pdColData = m_colData->PDColData; + for (int i = 0; i < pdColData.getSize(); i++) + { + { + std::shared_ptr<RbdContactConstraint> contactConstraint = + std::make_shared<RbdContactConstraint>( + m_rbdObjectA->getRigidBody(), nullptr, + pdColData[i].dirAtoB.normalized(), + pdColData[i].posB, + pdColData[i].penetrationDepth, + m_stiffness, + RbdConstraint::Side::A); + contactConstraint->compute(rbdModelA->getTimeStep()); + rbdModelA->addConstraint(contactConstraint); + } + + if (m_useFriction) + { + std::shared_ptr<RbdFrictionConstraint> frictionConstraint = + std::make_shared<RbdFrictionConstraint>( + m_rbdObjectA->getRigidBody(), nullptr, + pdColData[i].posB, + pdColData[i].dirAtoB.normalized(), + pdColData[i].penetrationDepth, + m_frictionalCoefficient, + RbdConstraint::Side::A); + frictionConstraint->compute(rbdModelA->getTimeStep()); + rbdModelA->addConstraint(frictionConstraint); + } + } +} + +void +RigidBodyCH::processB() +{ + std::shared_ptr<RigidBodyModel2> rbdModelB = m_rbdObjectB->getRigidBodyModel2(); + // Generate one-way constraints + PositionDirectionCollisionData& pdColData = m_colData->PDColData; + for (int i = 0; i < pdColData.getSize(); i++) + { + std::shared_ptr<RbdContactConstraint> contactConstraint = + std::make_shared<RbdContactConstraint>( + nullptr, m_rbdObjectB->getRigidBody(), + pdColData[i].dirAtoB.normalized(), + pdColData[i].posB, + pdColData[i].penetrationDepth, + m_stiffness, + RbdConstraint::Side::B); + contactConstraint->compute(rbdModelB->getTimeStep()); + rbdModelB->addConstraint(contactConstraint); + + if (m_useFriction) + { + std::shared_ptr<RbdFrictionConstraint> frictionConstraint = + std::make_shared<RbdFrictionConstraint>( + nullptr, m_rbdObjectB->getRigidBody(), + pdColData[i].posB, + pdColData[i].dirAtoB.normalized(), + pdColData[i].penetrationDepth, + m_frictionalCoefficient, + RbdConstraint::Side::B); + frictionConstraint->compute(rbdModelB->getTimeStep()); + rbdModelB->addConstraint(frictionConstraint); + } + } +} + +void +RigidBodyCH::processAB() +{ + // Generate one two-way constraint + std::shared_ptr<RigidBodyModel2> rbdModelAB = m_rbdObjectA->getRigidBodyModel2(); + PositionDirectionCollisionData& pdColData = m_colData->PDColData; + for (int i = 0; i < pdColData.getSize(); i++) + { + std::shared_ptr<RbdContactConstraint> contactConstraint = + std::make_shared<RbdContactConstraint>( + m_rbdObjectA->getRigidBody(), m_rbdObjectB->getRigidBody(), + pdColData[i].dirAtoB.normalized(), + pdColData[i].posB, + pdColData[i].penetrationDepth, + m_stiffness); + contactConstraint->compute(rbdModelAB->getTimeStep()); + rbdModelAB->addConstraint(contactConstraint); + + if (m_useFriction) + { + std::shared_ptr<RbdFrictionConstraint> frictionConstraint = + std::make_shared<RbdFrictionConstraint>( + m_rbdObjectA->getRigidBody(), m_rbdObjectB->getRigidBody(), + pdColData[i].posB, + pdColData[i].dirAtoB.normalized(), + pdColData[i].penetrationDepth, + m_frictionalCoefficient, + RbdConstraint::Side::AB); + frictionConstraint->compute(rbdModelAB->getTimeStep()); + rbdModelAB->addConstraint(frictionConstraint); + } + } +} +} +} \ No newline at end of file diff --git a/Source/CollisionHandling/imstkRigidBodyCH.h b/Source/CollisionHandling/imstkRigidBodyCH.h new file mode 100644 index 0000000000000000000000000000000000000000..87816827cf1fd19ed1886a1a86bbbb98720132c5 --- /dev/null +++ b/Source/CollisionHandling/imstkRigidBodyCH.h @@ -0,0 +1,80 @@ +/*========================================================================= + + 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 "imstkCollisionHandling.h" + +#include <vector> + +namespace imstk +{ +struct CollisionData; +namespace expiremental +{ +class RigidObject2; + +/// +/// \class RigidBodyContactHandler +/// +/// \brief Creates rigid body contact and frictional constraints given +/// collision data then adds them to the rigid body model, if rigid +/// objects use differing models, one-way contacts are added to both. +/// If only one rigid object is given, one-ways are used. +/// +class RigidBodyCH : public CollisionHandling +{ +public: + RigidBodyCH(const Side& side, + const std::shared_ptr<CollisionData> colData, + std::shared_ptr<RigidObject2> rbdObjectA, + std::shared_ptr<RigidObject2> rbdObjectB = nullptr, + const double stiffness = 0.0, + const double frictionalCoefficient = 0.8); + + RigidBodyCH() = delete; + + virtual ~RigidBodyCH() override = default; + +public: + /// + /// \brief Compute forces based on collision data + /// + void processCollisionData() override; + + void setStiffness(double stiffness) { m_stiffness = stiffness; } + void setFriction(double frictionalCoefficient) { m_frictionalCoefficient = frictionalCoefficient; } + void setUseFriction(bool useFriction) { m_useFriction = useFriction; } + +protected: + void processA(); + void processB(); + void processAB(); + +private: + std::shared_ptr<RigidObject2> m_rbdObjectA = nullptr; + std::shared_ptr<RigidObject2> m_rbdObjectB = nullptr; + double m_stiffness = 0.0; + double m_frictionalCoefficient = 0.8; + bool m_useFriction = true; +}; +} +} diff --git a/Source/CollisionHandling/imstkSPHCollisionHandling.cpp b/Source/CollisionHandling/imstkSPHCollisionHandling.cpp index 99670ce38a06b5cb74183a108335ebe09ccb8034..8e068628b4dc0fe420bb63f714038afc52c32384 100644 --- a/Source/CollisionHandling/imstkSPHCollisionHandling.cpp +++ b/Source/CollisionHandling/imstkSPHCollisionHandling.cpp @@ -21,8 +21,7 @@ #include "imstkSPHCollisionHandling.h" #include "imstkCollisionData.h" -#include "imstkLogger.h" -#include "imstkParallelUtils.h" +#include "imstkImplicitGeometryToPointSetCD.h" #include "imstkSPHModel.h" #include "imstkSPHObject.h" @@ -50,27 +49,23 @@ SPHCollisionHandling::processCollisionData() << "Invalid boundary friction coefficient (value must be in [0, 1])"; #endif - auto& state = SPHModel->getState(); - ParallelUtils::parallelFor(m_colData->MAColData.getSize(), - [&](const size_t idx) + SPHSimulationState& state = SPHModel->getState(); + std::function<void(uint32_t, Vec3d&)> solve = + [&](const uint32_t pidx, const Vec3d& penetrationVector) { - const MeshToAnalyticalCollisionDataElement& cd = m_colData->MAColData[idx]; - const uint32_t pidx = cd.nodeIdx; // Fluid particle index - Vec3d n = cd.penetrationVector; // This vector should point into solid object - // Correct particle position - state.getPositions()[pidx] -= n; + state.getPositions()[pidx] -= penetrationVector; - const auto nLengthSqr = n.squaredNorm(); + const auto nLengthSqr = penetrationVector.squaredNorm(); if (nLengthSqr < Real(1e-20)) // Normalize n { return; // Too little penetration: ignore } - n /= std::sqrt(nLengthSqr); + const Vec3d n = penetrationVector / std::sqrt(nLengthSqr); // Correct particle velocity: slip boundary condition with friction - const auto oldVel = state.getVelocities()[pidx]; - const auto vn = oldVel.dot(n); + const Vec3d& oldVel = state.getVelocities()[pidx]; + const double vn = oldVel.dot(n); // If particle is escaping the boundary, ignore it if (vn > 0) @@ -93,6 +88,41 @@ SPHCollisionHandling::processCollisionData() state.getVelocities()[pidx] = correctedVel; } - }); + }; + + // Solve analytical collision + for (int iter = 0; iter < m_iterations; iter++) + { + // Coming into this CH, CD has already been computed + if (iter != 0) + { + // Update the collision geometry + m_SPHObject->updateGeometries(); + // Compute collision again + m_colDetect->computeCollisionData(); + } + + ParallelUtils::parallelFor(m_colData->MAColData.getSize(), + [&](const size_t idx) + { + // Because of const, make some extra copies + const MeshToAnalyticalCollisionDataElement& cd = m_colData->MAColData[idx]; + const uint32_t pidx = cd.nodeIdx; // Fluid particle index + Vec3d penetrationVector = cd.penetrationVector; // This vector should point into solid object + + solve(pidx, penetrationVector); + }); + // Solve point/direction based collision + ParallelUtils::parallelFor(m_colData->PDColData.getSize(), + [&](const size_t idx) + { + // Because of const, make some extra copies + const PositionDirectionCollisionDataElement& cd = m_colData->PDColData[idx]; + const uint32_t pidx = cd.nodeIdx; // Fluid particle index + Vec3d penetrationVector = cd.dirAtoB * cd.penetrationDepth; // This vector should point into solid object + + solve(pidx, penetrationVector); + }); + } } } // end namespace imstk diff --git a/Source/CollisionHandling/imstkSPHCollisionHandling.h b/Source/CollisionHandling/imstkSPHCollisionHandling.h index e024c18d70375230690c0267cccf1c05a0c8e120..94aa1ee22d9f203d79ec0ebf51cce3c3cfb21815 100644 --- a/Source/CollisionHandling/imstkSPHCollisionHandling.h +++ b/Source/CollisionHandling/imstkSPHCollisionHandling.h @@ -20,13 +20,20 @@ =========================================================================*/ #pragma once + #include "imstkCollisionHandling.h" namespace imstk { +class ImplicitGeometryToPointSetCD; struct CollisionData; class SPHObject; +/// +/// \class SPHCollisionHandling +/// +/// \brief Supports SPH vs analytic and SPH vs Implicit Geometry +/// class SPHCollisionHandling : public CollisionHandling { public: @@ -36,6 +43,13 @@ public: SPHCollisionHandling() = delete; + virtual ~SPHCollisionHandling() override = default; + +public: + void setNumberOfIterations(int iterations) { this->m_iterations = iterations; } + + void setDetection(std::shared_ptr<ImplicitGeometryToPointSetCD> colDetect) { this->m_colDetect = colDetect; } + /// /// \brief Compute forces based on collision data /// @@ -43,5 +57,7 @@ public: private: std::shared_ptr<SPHObject> m_SPHObject = nullptr; + std::shared_ptr<ImplicitGeometryToPointSetCD> m_colDetect = nullptr; + int m_iterations = 1; }; } // end namespace imstk diff --git a/Source/CollisionHandling/imstkVirtualCouplingCH.cpp b/Source/CollisionHandling/imstkVirtualCouplingCH.cpp index 375d2d4f576c35405c059de59b7cdc30dbd8afad..394d9c967209f60ed88b3ae4ff2c8954926ad251 100644 --- a/Source/CollisionHandling/imstkVirtualCouplingCH.cpp +++ b/Source/CollisionHandling/imstkVirtualCouplingCH.cpp @@ -20,12 +20,9 @@ =========================================================================*/ #include "imstkVirtualCouplingCH.h" - +#include "imstkAnalyticalGeometry.h" #include "imstkCollidingObject.h" #include "imstkCollisionData.h" -#include "imstkAnalyticalGeometry.h" - -#include <g3log/g3log.hpp> namespace imstk { diff --git a/Source/CollisionHandling/imstkVirtualCouplingCH.h b/Source/CollisionHandling/imstkVirtualCouplingCH.h index 3ad40c87f577256666822a6c9362931296c99bad..6a8903f54e4c8132fc1818d5d50a9a32f107392a 100644 --- a/Source/CollisionHandling/imstkVirtualCouplingCH.h +++ b/Source/CollisionHandling/imstkVirtualCouplingCH.h @@ -21,7 +21,6 @@ #pragma once -// imstk #include "imstkCollisionHandling.h" #include "imstkMath.h" diff --git a/Source/Common/Modules/imstkLoopThreadObject.cpp b/Source/Common/Modules/imstkLoopThreadObject.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d117ffedf60218ed1071d22528484e3b441da87d --- /dev/null +++ b/Source/Common/Modules/imstkLoopThreadObject.cpp @@ -0,0 +1,167 @@ +/*========================================================================= + + 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 "imstkLoopThreadObject.h" +#include "imstkLogger.h" +#include "imstkMath.h" +#include "imstkTimer.h" + +namespace imstk +{ +LoopThreadObject::LoopThreadObject(std::string name, int loopDelay) : + ThreadObject(name), + m_frameCounter(std::make_shared<UPSCounter>()), + m_trackFPS(false), + m_loopDelay(loopDelay), + m_isInitialized(false) +{ +} + +void +LoopThreadObject::startThread() +{ + init(); + + // Keep active, wait for terminating call + std::chrono::steady_clock::time_point previous_t = std::chrono::steady_clock::now() - std::chrono::minutes(1); + std::chrono::steady_clock::time_point current_t; + long long elapsed; + while (m_status != ThreadStatus::Inactive) + { + if (m_requestedStatus == ThreadStatus::Inactive) + { + m_status = ThreadStatus::Inactive; + } + else if (m_requestedStatus == ThreadStatus::Paused) + { + m_status = ThreadStatus::Paused; + } + else if (m_requestedStatus == ThreadStatus::Running) + { + m_status = ThreadStatus::Running; + } + + if (m_status == ThreadStatus::Running) + { + // Short path to run module if loop delay = 0 + // (updating as fast as possible) + if (m_loopDelay < VERY_SMALL_EPSILON_D) + { + if (m_trackFPS) + { + m_frameCounter->setStartPointOfUpdate(); + } + + update(); + + if (m_trackFPS) + { + m_frameCounter->setEndPointOfUpdate(); + + std::cout << "\r" << this->getName() << " running at " + << m_frameCounter->getUPS() << " ups " << std::flush; + } + } + else + { + // If forcing a frequency, wait until enough time elapsed + current_t = std::chrono::steady_clock::now(); + elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(current_t - previous_t).count(); + if (elapsed >= m_loopDelay) + { + if (m_trackFPS) + { + m_frameCounter->setStartPointOfUpdate(); + } + + update(); + + if (m_trackFPS) + { + m_frameCounter->setEndPointOfUpdate(); + } + + previous_t = current_t; + } + } + } + } +} + +void +LoopThreadObject::setLoopDelay(const double milliseconds) +{ + if (milliseconds < 0) + { + LOG(WARNING) << "Module::setLoopDelay error: delay must be positive."; + return; + } + m_loopDelay = milliseconds; +} + +double +LoopThreadObject::getFrequency() const +{ + if (m_loopDelay < VERY_SMALL_EPSILON_D) + { + LOG(WARNING) << "Module::getFrequency warning: loop delay is set to 0ms, " + << "therefore not regulated by a frequency. Returning 0."; + return 0; + } + return 1000.0 / m_loopDelay; +} + +void +LoopThreadObject::setFrequency(const double f) +{ + if (f < 0) + { + LOG(WARNING) << "Module::setFrequency error: f must be positive, " + << "or equal to 0 to run the module in a closed loop."; + return; + } + if (f < VERY_SMALL_EPSILON_D) + { + m_loopDelay = 0; + return; + } + m_loopDelay = 1000.0 / f; +} + +unsigned int +LoopThreadObject::getUPS() const +{ + if (m_status != ThreadStatus::Running) + { + return 0; + } + + if (m_trackFPS) + { + return m_frameCounter->getUPS(); + } + else + { + LOG(WARNING) << "Frame counter is not enabled!"; + return 0; + } +} +} \ No newline at end of file diff --git a/Source/Common/Modules/imstkLoopThreadObject.h b/Source/Common/Modules/imstkLoopThreadObject.h new file mode 100644 index 0000000000000000000000000000000000000000..f8185b4973b243ad284a4e72d3dadbaa543ab543 --- /dev/null +++ b/Source/Common/Modules/imstkLoopThreadObject.h @@ -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. + +=========================================================================*/ + +#pragma once + +#include "imstkThreadObject.h" + +namespace imstk +{ +class UPSCounter; + +/// +/// \class LoopThreadObject +/// +/// \brief A thread object that defines its own basic loop and update function +/// Subclasses can define how to update +/// ?? +/// +class LoopThreadObject : public ThreadObject +{ +public: + LoopThreadObject(std::string name, int loopDelay = 0); + virtual ~LoopThreadObject() = default; + +public: + /// + /// \brief Get loop delay + /// + double getLoopDelay() const { return m_loopDelay; } + + /// + /// \brief Set the loop delay + /// + void setLoopDelay(const double milliseconds); + + /// + /// \brief Get loop delay + /// + double getFrequency() const; + + /// + /// \brief Set the loop delay + /// + void setFrequency(const double f); + + /// + /// \brief Enable frame count + /// + void enableFrameCount() { m_trackFPS = true; }; + /// + /// \brief Disable frame count + /// + void disableFrameCount() { m_trackFPS = false; }; + + /// \return true is frame count is already enabled + bool isFrameCountEnabled() const { return m_trackFPS; }; + + /// + /// \brief Get the updates per second + /// ?? UPS write it out + /// + unsigned int getUPS() const; + + /// + /// \brief Calls initThread on the thread object for subclasses to initialize + /// can only be called once + /// + void init() + { + if (!m_isInitialized) + { + initThread(); + m_isInitialized = true; + } + } + + /// + /// \brief Toggles the initialization flag so init can be called again + /// + void uninit() + { + m_isInitialized = false; + } + +public: + void update() + { + this->postEvent(Event(EventType::PostUpdate)); + updateThread(); + this->postEvent(Event(EventType::PreUpdate)); + } + +protected: + /// + /// \brief Start the thread + /// + virtual void startThread() override; + + /// + /// \brief Called right before thread is started + /// + virtual void initThread() { } + + /// + /// \brief Update the thread ?? + /// + virtual void updateThread() = 0; + +protected: + std::shared_ptr<UPSCounter> m_frameCounter; + double m_loopDelay; ///> Loop delay + bool m_trackFPS; ///> Flag to enable/diable FPS tracking + bool m_isInitialized; ///> Flag to avoid reinitialization +}; +} \ No newline at end of file diff --git a/Source/Common/Modules/imstkThreadObject.cpp b/Source/Common/Modules/imstkThreadObject.cpp new file mode 100644 index 0000000000000000000000000000000000000000..db22f32ca56da834090296005d6a099f4ac2fe30 --- /dev/null +++ b/Source/Common/Modules/imstkThreadObject.cpp @@ -0,0 +1,227 @@ +/*========================================================================= + + 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 "imstkThreadObject.h" +#include "imstkLogger.h" + +namespace imstk +{ +ThreadObject::ThreadObject(std::string name, ThreadStatus status) : + m_name(name), m_requestedStatus(status), m_parent(nullptr) +{ +} + +ThreadObject::~ThreadObject() +{ + // Stop if not yet + if (m_status != ThreadStatus::Inactive) + { + stop(true); + } +} + +void +ThreadObject::requestStatus(ThreadStatus status) +{ + // Copy the atomic + if (status == ThreadStatus::Inactive) + { + m_requestedStatus = ThreadStatus::Inactive; + } + else if (status == ThreadStatus::Paused) + { + m_requestedStatus = ThreadStatus::Paused; + } + else if (status == ThreadStatus::Running) + { + m_requestedStatus = ThreadStatus::Running; + } + // Children recieve their parents requests of status + for (size_t i = 0; i < m_children.size(); i++) + { + m_children[i]->requestStatus(status); + } +} + +void +ThreadObject::start(const bool sync) +{ + if (m_status != ThreadStatus::Inactive) + { + LOG(WARNING) << "Can not start '" << m_name << "'.\n" + << "Thread already/still active."; + return; + } + + this->postEvent(Event(EventType::Start, 5)); + + m_status = ThreadStatus::Running; + + // Start all of it's children first (does not wait) + for (size_t i = 0; i < m_children.size(); i++) + { + //m_children[i]->requestStatus(m_status); + m_children[i]->start(false); + } + + if (sync) + { + startThread(); + + m_status = ThreadStatus::Inactive; + + // Stop all of it's children + for (size_t i = 0; i < m_children.size(); i++) + { + m_children[i]->stop(true); + } + this->postEvent(Event(EventType::End, 5)); + m_requestedStatus = ThreadStatus::Running; + } + else + { + m_stlThread = std::thread( + [&]() + { + startThread(); + + m_status = ThreadStatus::Inactive; + + // Stop all of it's children + for (size_t i = 0; i < m_children.size(); i++) + { + m_children[i]->stop(true); + } + this->postEvent(Event(EventType::End, 5)); + m_requestedStatus = ThreadStatus::Running; + }); + } +} + +void +ThreadObject::stop(const bool sync) +{ + // Stop all of it's children first + for (size_t i = 0; i < m_children.size(); i++) + { + m_children[i]->stop(true); + } + + this->postEvent(Event(EventType::End, 5)); + + stopThread(); + if ((m_status == ThreadStatus::Inactive)) + { + LOG(WARNING) << "Can not end '" << m_name << "'.\n" << "Thread already inactive."; + return; + } + + m_requestedStatus = ThreadStatus::Inactive; + + // If sync, wait until the module actually stops before returning from function + if (sync) + { + while (m_status != ThreadStatus::Inactive) {} + + if (m_stlThread.joinable()) + { + m_stlThread.join(); + } + } +} + +void +ThreadObject::resume(const bool sync) +{ + if (m_status == ThreadStatus::Inactive) + { + return; + } + + this->postEvent(Event(EventType::Resume, 5)); + + resumeThread(); + if (m_status == ThreadStatus::Paused) + { + m_requestedStatus = ThreadStatus::Running; + + // If sync, wait until the module actually pauses before returning from function + if (sync) + { + while (m_status != ThreadStatus::Running) {} + } + } +} + +void +ThreadObject::pause(const bool sync) +{ + if (m_status == ThreadStatus::Inactive) + { + return; + } + + this->postEvent(Event(EventType::Pause, 5)); + + pauseThread(); + if (m_status == ThreadStatus::Running) + { + m_requestedStatus = ThreadStatus::Paused; + + // If sync, wait until the module actually pauses before returning from function + if (sync) + { + while (m_status != ThreadStatus::Paused) {} + } + } +} + +void +ThreadObject::addChildThread(std::shared_ptr<ThreadObject> childThreadObject) +{ + // If the module belongs to another parent + if (childThreadObject->m_parent != nullptr) + { + // Remove child, which should sync stop it + childThreadObject->m_parent->removeChildThread(childThreadObject); + } + + m_children.push_back(childThreadObject); + childThreadObject->m_parent = this; + + // Request the child have the parents status + // This may start it, pause it, start in pause, etc + //childThreadObject->requestStatus(m_status); +} + +void +ThreadObject::removeChildThread(std::shared_ptr<ThreadObject> childThreadObject) +{ + auto i = std::find(m_children.begin(), m_children.end(), childThreadObject); + if (i != m_children.end()) + { + // Stop in sync + (*i)->stop(true); + m_children.erase(i); + childThreadObject->m_parent = nullptr; + } +} +} diff --git a/Source/Common/Modules/imstkThreadObject.h b/Source/Common/Modules/imstkThreadObject.h new file mode 100644 index 0000000000000000000000000000000000000000..4b6cf8137c41fbf2b9d8b9dcae6872977f01fae9 --- /dev/null +++ b/Source/Common/Modules/imstkThreadObject.h @@ -0,0 +1,148 @@ +/*========================================================================= + + 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 "imstkEventObject.h" + +#include <string> +#include <atomic> +#include <thread> +#include <vector> + +namespace imstk +{ +/// +/// \brief Enumerations for the status of the thread +/// +enum class ThreadStatus +{ + Running, + Paused, + Inactive +}; + +/// +/// \class ThreadObject +/// +/// \brief Wraps Thread with an object oriented base class suited for real time, +/// persistent threads ?? +/// +class ThreadObject : public EventObject +{ +public: + virtual ~ThreadObject() override; + +protected: + /// + /// \brief Set status to launch into paused state + /// \param: Name of the thread + /// \param: Desired status when this starts + /// + ThreadObject(std::string name, ThreadStatus requestedStatus = ThreadStatus::Running); + +public: + /// + /// \brief Get the status of the thread + /// + ThreadStatus getStatus() const { return m_status; } + + /// + /// \brief Get the name of the thread + /// + const std::string& getName() const { return m_name; } + + /// + /// \brief An agglomeration of the start/stop/resume/pause calls + /// \param: Desired status + /// \param: When true, returns after status has changed to desired. When false, returns immediately + /// + void requestStatus(ThreadStatus status); + +public: + /// + /// \brief Start the thread and all its children + /// children are started before parents + /// \param sync: When true, returns after thread is complete. When false, returns immediately + /// + virtual void start(const bool sync = true); + + /// + /// \brief End/terminate the thread + /// \param sync: When true, returns after stop complete (like a thread join). + /// When false, returns immediately + /// + virtual void stop(const bool sync = true); + + /// + /// \brief Resume the thread + /// \param sync: When true, returns after resume. When false, returns immediately + /// + virtual void resume(const bool sync = false); + + /// + /// \brief Pause the thread + /// \param sync: When true, returns after thread paused. When false, returns immediately + /// + virtual void pause(const bool sync = true); + + /// + /// \brief Adds a child, this thread will start when *this* does + /// If *this* is already running, it will start immediately + /// If *this* is paused, it will start paused + /// + void addChildThread(std::shared_ptr<ThreadObject> childThreadObject); + + /// + /// \brief Stops and then removes a child + /// + void removeChildThread(std::shared_ptr<ThreadObject> childThreadObject); + +protected: + /// + /// \brief Called when the thread starts + /// + virtual void startThread() { } + + /// + /// \brief Called when the thread stops + /// + virtual void stopThread() { } + + /// + /// \brief Called before the thread resumes + /// + virtual void resumeThread() { } + + /// + /// \brief Called before the thread pauses + /// + virtual void pauseThread() { } + +protected: + std::atomic<ThreadStatus> m_status{ ThreadStatus::Inactive }; ///> Thread status + std::atomic<ThreadStatus> m_requestedStatus{ ThreadStatus::Running }; ///> Requested status + std::vector<std::shared_ptr<ThreadObject>> m_children; ///> Child threads + ThreadObject* m_parent; ///> Parent thread, may only have one (or none) + std::string m_name; ///> Name of the thread + std::thread m_stlThread; ///> Used for the thread +}; +} \ No newline at end of file diff --git a/Source/Common/Parallel/imstkParallelReduce.h b/Source/Common/Parallel/imstkParallelReduce.h index f26c0e7e76887f3a5cea161458507805c3b4c54f..37142eb0ff510d283d13514b9443ed7995327bba 100644 --- a/Source/Common/Parallel/imstkParallelReduce.h +++ b/Source/Common/Parallel/imstkParallelReduce.h @@ -22,6 +22,7 @@ #pragma once #include "imstkMath.h" + #include <tbb/tbb.h> #undef min @@ -31,6 +32,44 @@ namespace imstk { namespace ParallelUtils { +/// +/// \brief Private helper class, providing operator() using in std::parallel_reduce +/// for finding range of a container with specified begin/end/operator[],operator++ functions +/// +template<class ContainerType> +class RangeFunctor +{ +public: + RangeFunctor(const ContainerType& data) : m_Data(data) { } + RangeFunctor(RangeFunctor& pObj, tbb::split) : m_Data(pObj.m_Data) { } + + // Prohibit copying + RangeFunctor() = delete; + RangeFunctor& operator=(const RangeFunctor&) = delete; + + void operator()(const tbb::blocked_range<size_t>& r) + { + for (size_t i = r.begin(); i != r.end(); i++) + { + m_Max = m_Max > m_Data[i] ? m_Max : m_Data[i]; + m_Min = m_Max < m_Data[i] ? m_Min : m_Data[i]; + } + } + + void join(RangeFunctor& pObj) + { + m_Max = m_Max > pObj.m_Max ? m_Max : pObj.m_Max; + m_Min = m_Min < pObj.m_Min ? m_Min : pObj.m_Min; + } + + Vec2d getRange() const { return Vec2d(m_Min, m_Max); } + +private: + Real m_Min = std::numeric_limits<Real>::max(); + Real m_Max = std::numeric_limits<Real>::min(); + const ContainerType& m_Data; +}; + /// /// \brief Private helper class, providing operator() using in std::parallel_reduce /// for finding max L2 norm of an array of Vec3r diff --git a/Source/Common/Parallel/imstkThreadManager.cpp b/Source/Common/Parallel/imstkThreadManager.cpp index f242cc27b1a89efe0847044eec9d3a015a894dc9..1aba79875405219af47be5feae8471f1a61c6681 100644 --- a/Source/Common/Parallel/imstkThreadManager.cpp +++ b/Source/Common/Parallel/imstkThreadManager.cpp @@ -20,8 +20,7 @@ =========================================================================*/ #include "imstkThreadManager.h" - -#include <g3log/g3log.hpp> +#include "imstkLogger.h" namespace imstk { @@ -50,5 +49,11 @@ ThreadManager::setOptimalParallelism() { setThreadPoolSize(static_cast<size_t>(tbb::task_scheduler_init::default_num_threads())); } + +size_t +ThreadManager::getThreadPoolSize() +{ + return s_tbbGlobalControl->active_value(tbb::global_control::max_allowed_parallelism); +} } // end namespace ParallelUtils } // end namespace imstk diff --git a/Source/Common/Parallel/imstkThreadManager.h b/Source/Common/Parallel/imstkThreadManager.h index 256064b8fda970e4608015a554fdea7fedb915e7..263bef9a3f8768ed6925ddf373b9a80aded61de1 100644 --- a/Source/Common/Parallel/imstkThreadManager.h +++ b/Source/Common/Parallel/imstkThreadManager.h @@ -45,6 +45,11 @@ public: /// static void setOptimalParallelism(); + /// + /// \brief Returns the size of the thread pool + /// + static size_t getThreadPoolSize(); + private: /// /// \brief Global variable for controlling maximum number of worker threads diff --git a/Source/Common/TaskGraph/imstkSequentialTaskGraphController.cpp b/Source/Common/TaskGraph/imstkSequentialTaskGraphController.cpp index f9cccef2ad552d2db107bf901b2b2783084f7fd5..f65496bbcfb8c1e9233fa9f86466d4f9fdce3e75 100644 --- a/Source/Common/TaskGraph/imstkSequentialTaskGraphController.cpp +++ b/Source/Common/TaskGraph/imstkSequentialTaskGraphController.cpp @@ -21,7 +21,6 @@ #include "imstkSequentialTaskGraphController.h" #include "imstkTaskGraph.h" -#include "imstkTaskNode.h" namespace imstk { diff --git a/Source/Common/TaskGraph/imstkTaskGraph.cpp b/Source/Common/TaskGraph/imstkTaskGraph.cpp index fd5cf84bd808accf3145a309904fcc89995932c1..1f0555a9d9e2aec4de776eac7d7c5fbe807759cc 100644 --- a/Source/Common/TaskGraph/imstkTaskGraph.cpp +++ b/Source/Common/TaskGraph/imstkTaskGraph.cpp @@ -21,9 +21,7 @@ limitations under the License. #include "imstkTaskGraph.h" #include "imstkLogger.h" -#include "imstkTaskNode.h" -#include <queue> -#include <set> + #include <stack> namespace imstk diff --git a/Source/Common/TaskGraph/imstkTaskGraph.h b/Source/Common/TaskGraph/imstkTaskGraph.h index 79c2d99c5a0e8a4176c6a085217c003dba877b12..3e7d00bd8e68059d42efe5685862966a95286c7a 100644 --- a/Source/Common/TaskGraph/imstkTaskGraph.h +++ b/Source/Common/TaskGraph/imstkTaskGraph.h @@ -22,6 +22,7 @@ limitations under the License. #pragma once #include "imstkTaskNode.h" + #include <list> #include <memory> #include <unordered_map> diff --git a/Source/Common/TaskGraph/imstkTaskGraphVizWriter.cpp b/Source/Common/TaskGraph/imstkTaskGraphVizWriter.cpp index 2bd010b468cb5e2e5361d7661209c010c3fee0d8..768b3b9508bb7eb495e0c61994f5955343ec2e43 100644 --- a/Source/Common/TaskGraph/imstkTaskGraphVizWriter.cpp +++ b/Source/Common/TaskGraph/imstkTaskGraphVizWriter.cpp @@ -23,7 +23,6 @@ limitations under the License. #include "imstkLogger.h" #include "imstkTaskGraph.h" #include "imstkColor.h" -#include <fstream> namespace imstk { @@ -81,7 +80,7 @@ TaskGraphVizWriter::write() } file << - "digraph imstkDependency\n" + "digraph imstkTaskGraph\n" "{\n" "style=filled;\n" "color=lightgrey;\n" diff --git a/Source/Common/TaskGraph/imstkTaskNode.h b/Source/Common/TaskGraph/imstkTaskNode.h index 10bdccb27e74e95685e4c6f8fcab976febf36ecb..90ed0c47ca99038eca2db318bfcd134e1e28994c 100644 --- a/Source/Common/TaskGraph/imstkTaskNode.h +++ b/Source/Common/TaskGraph/imstkTaskNode.h @@ -36,7 +36,7 @@ class TaskNode public: TaskNode() = default; TaskNode(std::function<void()> func, std::string name = "none", bool isCritical = false) : - m_func(func), m_name(name), m_isCritical(isCritical), m_computeTime(0.0) + m_name(name), m_isCritical(isCritical), m_computeTime(0.0), m_func(func) { } diff --git a/Source/Common/TaskGraph/imstkTbbTaskGraphController.cpp b/Source/Common/TaskGraph/imstkTbbTaskGraphController.cpp index 15581278657cd1de25eca99c46b5d7accbf8fec6..63fb4f6c0e2d391f2cc210ffd69686f6291c4533 100644 --- a/Source/Common/TaskGraph/imstkTbbTaskGraphController.cpp +++ b/Source/Common/TaskGraph/imstkTbbTaskGraphController.cpp @@ -21,6 +21,7 @@ #include "imstkTbbTaskGraphController.h" #include "imstkTaskGraph.h" + #include <tbb/tbb.h> namespace imstk @@ -97,6 +98,7 @@ TbbTaskGraphController::execute() // Extra ref count on the final task finalTask->increment_ref_count(); finalTask->spawn_and_wait_for_all(*startTask); + finalTask->execute(); // Execute final task explicitly tbb::task::destroy(*finalTask); } diff --git a/Source/Common/Testing/imstkModuleTest.cpp b/Source/Common/Testing/imstkModuleTest.cpp index c86ed5936381f35294d14413aa70100d6f9f9d38..d8f41bff076bdce95c996c30bdc1e5b817074988 100644 --- a/Source/Common/Testing/imstkModuleTest.cpp +++ b/Source/Common/Testing/imstkModuleTest.cpp @@ -20,36 +20,28 @@ =========================================================================*/ #include "gtest/gtest.h" -#include "gmock/gmock.h" #include <g3log/g3log.hpp> -#include "imstkMath.h" -#include "imstkModule.h" - -#include <thread> -#include <chrono> +#include "imstkLoopThreadObject.h" namespace imstk { /// /// \brief TODO /// -class ModuleMock : public Module +class LoopThreadObjectMock : public LoopThreadObject { public: - - ModuleMock() : Module("modulemock") {} - ~ModuleMock() = default; + LoopThreadObjectMock() : LoopThreadObject("modulemock") { } + ~LoopThreadObjectMock() override = default; bool m_init = false; - bool m_run = false; bool m_cleanup = false; protected: - - inline void initModule() final { m_init = true; } - inline void runModule() final { m_run = true; } - inline void cleanUpModule() final { m_cleanup = true; } + inline void initThread() override { m_init = true; } + inline void updateThread() override { } + inline void stopThread() override { m_cleanup = true; } }; } @@ -61,141 +53,90 @@ using namespace imstk; class imstkModuleTest : public ::testing::Test { protected: - ModuleMock m_module; + LoopThreadObjectMock m_threadObject; }; TEST_F(imstkModuleTest, GetName) { - EXPECT_EQ(m_module.getName(), "modulemock"); + EXPECT_EQ(m_threadObject.getName(), "modulemock"); } TEST_F(imstkModuleTest, GetSetLoopDelay) { - m_module.setLoopDelay(2); - EXPECT_EQ(m_module.getLoopDelay(), 2); + m_threadObject.setLoopDelay(2); + EXPECT_EQ(m_threadObject.getLoopDelay(), 2); - m_module.setLoopDelay(0.003); - EXPECT_EQ(m_module.getLoopDelay(), 0.003); + m_threadObject.setLoopDelay(0.003); + EXPECT_EQ(m_threadObject.getLoopDelay(), 0.003); - m_module.setLoopDelay(400000000); - EXPECT_EQ(m_module.getLoopDelay(), 400000000); + m_threadObject.setLoopDelay(400000000); + EXPECT_EQ(m_threadObject.getLoopDelay(), 400000000); - m_module.setLoopDelay(0); - EXPECT_EQ(m_module.getLoopDelay(), 0); + m_threadObject.setLoopDelay(0); + EXPECT_EQ(m_threadObject.getLoopDelay(), 0); - m_module.setLoopDelay(-5); - EXPECT_GE(m_module.getLoopDelay(), 0); + m_threadObject.setLoopDelay(-5); + EXPECT_GE(m_threadObject.getLoopDelay(), 0); } TEST_F(imstkModuleTest, SetFrequency) { - m_module.setFrequency(60); - EXPECT_EQ(m_module.getLoopDelay(), 1000.0 / 60.0); + m_threadObject.setFrequency(60); + EXPECT_EQ(m_threadObject.getLoopDelay(), 1000.0 / 60.0); - m_module.setFrequency(0.003); - EXPECT_EQ(m_module.getLoopDelay(), 1000.0 / 0.003); + m_threadObject.setFrequency(0.003); + EXPECT_EQ(m_threadObject.getLoopDelay(), 1000.0 / 0.003); - m_module.setFrequency(400000000); - EXPECT_EQ(m_module.getLoopDelay(), 1000.0 / 400000000); + m_threadObject.setFrequency(400000000); + EXPECT_EQ(m_threadObject.getLoopDelay(), 1000.0 / 400000000); - m_module.setFrequency(0); - EXPECT_EQ(m_module.getLoopDelay(), 0); + m_threadObject.setFrequency(0); + EXPECT_EQ(m_threadObject.getLoopDelay(), 0); - m_module.setFrequency(-5); - EXPECT_GE(m_module.getLoopDelay(), 0); + m_threadObject.setFrequency(-5); + EXPECT_GE(m_threadObject.getLoopDelay(), 0); } TEST_F(imstkModuleTest, GetFrequency) { - m_module.setLoopDelay(2); - EXPECT_EQ(m_module.getFrequency(), 1000.0 / 2); + m_threadObject.setLoopDelay(2); + EXPECT_EQ(m_threadObject.getFrequency(), 1000.0 / 2); - m_module.setLoopDelay(0.003); - EXPECT_EQ(m_module.getFrequency(), 1000.0 / 0.003); + m_threadObject.setLoopDelay(0.003); + EXPECT_EQ(m_threadObject.getFrequency(), 1000.0 / 0.003); - m_module.setLoopDelay(400000000); - EXPECT_EQ(m_module.getFrequency(), 1000.0 / 400000000); + m_threadObject.setLoopDelay(400000000); + EXPECT_EQ(m_threadObject.getFrequency(), 1000.0 / 400000000); - m_module.setLoopDelay(0); - EXPECT_EQ(m_module.getFrequency(), 0); + m_threadObject.setLoopDelay(0); + EXPECT_EQ(m_threadObject.getFrequency(), 0); - m_module.setLoopDelay(-5); - EXPECT_GE(m_module.getFrequency(), 0); + m_threadObject.setLoopDelay(-5); + EXPECT_GE(m_threadObject.getFrequency(), 0); } + TEST_F(imstkModuleTest, ControlModule) { - ASSERT_EQ(m_module.getStatus(), ModuleStatus::Inactive); - - m_module.run(); - ASSERT_EQ(m_module.getStatus(), ModuleStatus::Inactive); - ASSERT_FALSE(m_module.m_init); - ASSERT_FALSE(m_module.m_run); - ASSERT_FALSE(m_module.m_cleanup); - - m_module.pause(); - ASSERT_EQ(m_module.getStatus(), ModuleStatus::Inactive); - ASSERT_FALSE(m_module.m_init); - ASSERT_FALSE(m_module.m_run); - ASSERT_FALSE(m_module.m_cleanup); - - m_module.end(); - ASSERT_EQ(m_module.getStatus(), ModuleStatus::Inactive); - ASSERT_FALSE(m_module.m_init); - ASSERT_FALSE(m_module.m_run); - ASSERT_TRUE(m_module.m_cleanup); - - auto t = std::thread([this] { m_module.start(); }); - std::this_thread::sleep_for(std::chrono::milliseconds(500)); - ASSERT_EQ(m_module.getStatus(), ModuleStatus::Running); - ASSERT_TRUE(m_module.m_init); - ASSERT_TRUE(m_module.m_run); - - m_module.pause(); - ASSERT_EQ(m_module.getStatus(), ModuleStatus::Paused); - m_module.m_run = false; - std::this_thread::sleep_for(std::chrono::milliseconds(500)); - ASSERT_TRUE(m_module.m_init); - ASSERT_FALSE(m_module.m_run); - - m_module.run(); - ASSERT_EQ(m_module.getStatus(), ModuleStatus::Running); - std::this_thread::sleep_for(std::chrono::milliseconds(500)); - ASSERT_TRUE(m_module.m_init); - ASSERT_TRUE(m_module.m_run); - - m_module.end(); - ASSERT_EQ(m_module.getStatus(), ModuleStatus::Inactive); - std::this_thread::sleep_for(std::chrono::milliseconds(500)); - ASSERT_TRUE(m_module.m_init); - ASSERT_TRUE(m_module.m_run); - ASSERT_TRUE(m_module.m_cleanup); - - t.join(); - m_module.m_init = m_module.m_run = m_module.m_cleanup = false; - - t = std::thread([this] { m_module.start(); }); - std::this_thread::sleep_for(std::chrono::milliseconds(500)); - ASSERT_EQ(m_module.getStatus(), ModuleStatus::Running); - ASSERT_TRUE(m_module.m_init); - ASSERT_TRUE(m_module.m_run); - ASSERT_FALSE(m_module.m_cleanup); - - m_module.pause(); - ASSERT_EQ(m_module.getStatus(), ModuleStatus::Paused); - m_module.m_run = false; - std::this_thread::sleep_for(std::chrono::milliseconds(500)); - ASSERT_TRUE(m_module.m_init); - ASSERT_FALSE(m_module.m_run); - ASSERT_FALSE(m_module.m_cleanup); - - m_module.end(); - ASSERT_EQ(m_module.getStatus(), ModuleStatus::Inactive); - std::this_thread::sleep_for(std::chrono::milliseconds(500)); - ASSERT_TRUE(m_module.m_init); - ASSERT_FALSE(m_module.m_run); - ASSERT_TRUE(m_module.m_cleanup); - - t.join(); + ASSERT_EQ(m_threadObject.getStatus(), ThreadStatus::Inactive); + + // Test start/stop/pause + ASSERT_FALSE(m_threadObject.m_init); + + m_threadObject.start(false); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + ASSERT_EQ(m_threadObject.getStatus(), ThreadStatus::Running); + ASSERT_TRUE(m_threadObject.m_init); + ASSERT_FALSE(m_threadObject.m_cleanup); + + m_threadObject.pause(true); + ASSERT_EQ(m_threadObject.getStatus(), ThreadStatus::Paused); + ASSERT_TRUE(m_threadObject.m_init); + ASSERT_FALSE(m_threadObject.m_cleanup); + + m_threadObject.stop(true); + ASSERT_EQ(m_threadObject.getStatus(), ThreadStatus::Inactive); + ASSERT_TRUE(m_threadObject.m_init); + ASSERT_TRUE(m_threadObject.m_cleanup); } /// diff --git a/Source/Common/Utils/imstkTimer.cpp b/Source/Common/Utils/imstkTimer.cpp index c2905cc25803fb07f2d38139a64b3f851f1c2e2a..4668e803dcf7f26895df6f98c1c2ffb6e8a9b731 100644 --- a/Source/Common/Utils/imstkTimer.cpp +++ b/Source/Common/Utils/imstkTimer.cpp @@ -20,6 +20,7 @@ =========================================================================*/ #include "imstkTimer.h" +#include "imstkLogger.h" namespace imstk { diff --git a/Source/Common/Utils/imstkTimer.h b/Source/Common/Utils/imstkTimer.h index 4621c0cf55c9a2b982b11753e45c31588f5e4887..e175d696130daa47a14911a5c23e86f92b32f0ae 100644 --- a/Source/Common/Utils/imstkTimer.h +++ b/Source/Common/Utils/imstkTimer.h @@ -20,11 +20,9 @@ =========================================================================*/ #pragma once - -#include "imstkLogger.h" - #include <chrono> #include <ctime> +#include <memory> #include <string> #include <vector> diff --git a/Source/Common/imstkAbstractDataArray.h b/Source/Common/imstkAbstractDataArray.h new file mode 100644 index 0000000000000000000000000000000000000000..cf524566cafb923444d9b062e01507999ab6b02e --- /dev/null +++ b/Source/Common/imstkAbstractDataArray.h @@ -0,0 +1,85 @@ +/*========================================================================= + + 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 "imstkTypes.h" +#include "imstkEventObject.h" + +namespace imstk +{ +/// +/// \class AbstractDataArray +/// +/// \brief This class serves as the base class of DataArray, for typeless use +/// \todo: Component support, AOS/SOA design +/// +class AbstractDataArray : public EventObject +{ +// Users should not be able to construct +protected: + AbstractDataArray() = default; + + /// + /// \brief Ensure all observers are disconnected + /// + virtual ~AbstractDataArray() { }; + +public: + /// + /// \brief Resizes the array, may reallocate + /// + virtual void resize(const size_t count) = 0; + + /// + /// \brief Reserves a size for the array in memory, may reallocate + /// + virtual void reserve(const size_t count) = 0; + + /// + /// \brief Returns the number of elements in the array + /// + virtual size_t size() const = 0; + + /// + /// \brief Returns void pointer to data + /// + virtual void* getVoidPointer() = 0; + + /// + /// \brief Returns the scalar type of this array + /// + inline const ScalarType getScalarType() { return m_scalarType; } + +public: + /// + /// \brief emits signal to all observers, informing them on the current address + /// in memory and size of array + /// + inline void modified() { this->postEvent(Event(EventType::Modified)); } + +protected: + void setType(const ScalarType type) { this->m_scalarType = type; } + +private: + ScalarType m_scalarType; +}; +} \ No newline at end of file diff --git a/Source/Common/imstkColor.cpp b/Source/Common/imstkColor.cpp index c36cece067b66a6428f97a8a2d24b25483a4f214..926019a2b76e5880601524bbc0f4a3cc74050a09 100644 --- a/Source/Common/imstkColor.cpp +++ b/Source/Common/imstkColor.cpp @@ -21,8 +21,8 @@ #include "imstkColor.h" #include "imstkLogger.h" + #include <iomanip> -#include <sstream> namespace imstk { @@ -47,10 +47,10 @@ Color Color::Marigold(0.9, 0.9, 0.4); Color::Color() { - rgba[0] = 0.8f; - rgba[1] = 0.8f; - rgba[2] = 0.8f; - rgba[3] = 1.0f; + rgba[0] = 0.8; + rgba[1] = 0.8; + rgba[2] = 0.8; + rgba[3] = 1.0; } Color::Color(const double r, const double g, const double b, const double a) diff --git a/Source/Common/imstkColor.h b/Source/Common/imstkColor.h index beb2ed911e2117e46e34d561b79019e7214a01b3..ea659e5c7137730e189e8cdc470b2fff78d130cd 100644 --- a/Source/Common/imstkColor.h +++ b/Source/Common/imstkColor.h @@ -24,7 +24,9 @@ #include <iostream> /// \todo remove nameless union/struct in the future +#ifdef WIN32 #pragma warning(disable : 4201) +#endif namespace imstk { /// @@ -123,7 +125,9 @@ struct Color static Color Teal; static Color Marigold; }; +#ifdef WIN32 #pragma warning(default : 4201) +#endif /// /// \brief Multiplication operators diff --git a/Source/Common/imstkColorFunction.h b/Source/Common/imstkColorFunction.h index 3b3577b7ebfde9ee7bb24ab205cef81a162fdf0f..f011a7fe4c8b777261361e26c31b00fb01608f56 100644 --- a/Source/Common/imstkColorFunction.h +++ b/Source/Common/imstkColorFunction.h @@ -50,7 +50,7 @@ public: virtual ~ColorFunction() = default; public: - size_t getNumberOfColors() const { return m_table.size(); } + int getNumberOfColors() const { return static_cast<int>(m_table.size()); } const Color& getColor(int i) const { return m_table[i]; } const Vec2d& getRange() const { return m_range; } const ColorSpace& getColorSpace() const { return m_colorSpace; } diff --git a/Source/Common/imstkDataArray.h b/Source/Common/imstkDataArray.h new file mode 100644 index 0000000000000000000000000000000000000000..d9da7d352d6bc4547428fc0a3ae06f7404afa7a7 --- /dev/null +++ b/Source/Common/imstkDataArray.h @@ -0,0 +1,101 @@ +/*========================================================================= + + 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 "imstkAbstractDataArray.h" +#include "imstkParallelReduce.h" + +#include <vector> + +namespace imstk +{ +/// +/// \class DataArray +/// +/// \brief This class serves as a wrapping to STL vector, it also provides modified callback +/// \todo: Support tuples/components +/// +template<class T> +class DataArray : public AbstractDataArray +{ +public: + using iterator = typename std::vector<T>::iterator; + using const_iterator = typename std::vector<T>::const_iterator; + +public: + /// + /// \brief Constructs an empty data array + /// + DataArray() { setType(TypeTemplateMacro(T)); } + + /// + /// \brief Constructs a data array with count elements + /// + DataArray(size_t count) : vec(count) { setType(TypeTemplateMacro(T)); } + + /// + /// \brief Constructs from intializer list + /// + DataArray(std::initializer_list<T> list) : vec(list.begin(), list.end()) { setType(TypeTemplateMacro(T)); } + +public: + inline void resize(const size_t newCount) override { vec.resize(newCount); } + + inline void push_back(const T& val) { vec.push_back(val); } + inline void push_back(const T&& val) { vec.push_back(val); } + + inline void erase(const const_iterator& element) { vec.erase(element); } + + inline void reserve(const size_t count) override { vec.reserve(count); } + + inline size_t size() const override { return vec.size(); } + + inline T* getPointer() { return vec.data(); } + inline void* getVoidPointer() override { return static_cast<void*>(vec.data()); } + + inline T& operator[](const size_t pos) { return vec[pos]; } + inline const T& operator[](const size_t pos) const { return vec[pos]; } + + /// + /// \brief Allow initialization from initializer list, ie: DataArray<int> arr = { 1, 2 } + /// + template<typename U> + DataArray<U>& operator=(std::initializer_list<U> list) + { + vec = std::vector<U>(list.begin(), list.end()); + return *this; + } + + /// + /// \brief Computes the scalar range + /// + inline Vec2d getScalarRange() const + { + ParallelUtils::RangeFunctor<std::vector<T>> pObj(vec); + tbb::parallel_reduce(tbb::blocked_range<size_t>(0, vec.size()), pObj); + return pObj.getRange(); + } + +private: + std::vector<T> vec; +}; +} \ No newline at end of file diff --git a/Source/Common/imstkDataLogger.cpp b/Source/Common/imstkDataLogger.cpp index 9aff6685c21de47b0d0ce53718d02a5775a17158..97cf41665f50122db95a3b3d7a71a27d9b8b4b9e 100644 --- a/Source/Common/imstkDataLogger.cpp +++ b/Source/Common/imstkDataLogger.cpp @@ -21,7 +21,6 @@ #include "imstkDataLogger.h" #include "imstkLogger.h" -#include <cstring> namespace imstk { diff --git a/Source/SceneEntities/Objects/imstkKinematicState.cpp b/Source/Common/imstkEventObject.cpp similarity index 96% rename from Source/SceneEntities/Objects/imstkKinematicState.cpp rename to Source/Common/imstkEventObject.cpp index 46860e82a45583ec9e4be6f776b714c9137a4aa2..caa249656518416a617770ba332fe5c8d62f4407 100644 --- a/Source/SceneEntities/Objects/imstkKinematicState.cpp +++ b/Source/Common/imstkEventObject.cpp @@ -19,6 +19,8 @@ =========================================================================*/ +#include "imstkEventObject.h" + namespace imstk { -} +} \ No newline at end of file diff --git a/Source/Common/imstkEventObject.h b/Source/Common/imstkEventObject.h new file mode 100644 index 0000000000000000000000000000000000000000..8582fb7b82f241dd86325c680b0991a65f86e86c --- /dev/null +++ b/Source/Common/imstkEventObject.h @@ -0,0 +1,438 @@ +/*========================================================================= + + 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 <algorithm> +#include <functional> +#include <list> +#include <memory> +//#include <tbb/concurrent_priority_queue.h> +#include <tbb/concurrent_queue.h> +#include <tbb/concurrent_unordered_map.h> + +namespace imstk +{ +enum class EventType +{ + AnyEvent, + Start, + End, + Resume, + Pause, + Modified, + KeyPress, + VRButtonPress, + MouseEvent, + PreUpdate, + PostUpdate, + Configure + //?? add one for collision? +}; + +/// +/// \class Event +/// +/// \brief Base class for events which contain a type, priority, and data +/// priority defaults to 0 and uses a greater than comparator. Negatives are +/// allowed. +/// +class Event +{ +public: + Event() : m_type(EventType::AnyEvent), m_priority(0) { } + Event(EventType type, int priority = 0) : m_type(type), m_priority(priority) { } + virtual ~Event() = default; + +public: + bool operator<(const Event& other) const + { + return m_priority < other.m_priority; + } + + bool operator>(const Event& other) const + { + return m_priority > other.m_priority; + } + +public: + EventType m_type; + int m_priority; +}; + +/// +/// \brief Stores everything needed to invoke an event +/// ie: where and with what +/// +class Command +{ +public: + Command() : m_call(nullptr), m_event(nullptr) { } + Command(std::function<void(Event*)> call, Event* event) : m_call(call), m_event(event) { } + +public: + bool operator<(const Command& other) const + { + return *m_event > *other.m_event; + } + +public: + std::function<void(Event*)> m_call; + Event* m_event; +}; + +class EventObject; + +template<class T, class RecieverType> +static void connect(EventObject*, EventType, RecieverType*, void (RecieverType::* func)(T*)); +template<class T> +static void connect(EventObject*, EventType, std::function<void(T*)>); + +template<class T, class RecieverType> +static void queueConnect(EventObject*, EventType, RecieverType*, void (RecieverType::* func)(T*)); +template<class T> +static void queueConnect(EventObject*, EventType, EventObject*, std::function<void(T*)>); + +static void disconnect(EventObject*, EventObject*, EventType); + +/// +/// \class imstkEventObject +/// +/// \brief imstkEventObject is the base abstract class for all objects in iMSTK that +/// can recieve and emit events. It supports direct and queued observer functions. +/// Direct observers recieve events immediately on the same thread +/// This can either be posted on an object or be a function pointer +/// Queued observers recieve events within their queue which they can process whenever +/// they like. +/// These can be connected with the connect/queuedConnect/disconnect functions +/// \todo ThreadObject affinity +/// +class EventObject +{ +public: + using Observer = std::pair<EventObject*, std::function<void (Event*)>>; + +public: + virtual ~EventObject() = default; + +public: + /// + /// \brief Emits the event + /// Direct observers will be immediately called, in sync + /// Queued observers will receive the Command in their queue for later + /// execution, reciever must implement doEvent + /// + template<typename T> + void postEvent(const T& e) + { + // For every direct observer + for (std::list<Observer>::iterator i = directObservers[e.m_type].begin(); i != directObservers[e.m_type].end(); i++) + { + // We don't need an object (i->first) to call + // Call its function, if it exists, otherwise remove observer + if (i->second != nullptr) + { + i->second(new T(e)); + } + else + { + i = directObservers[e.m_type].erase(i); + } + } + + // For every queued observer + for (std::list<Observer>::iterator i = queuedObservers[e.m_type].begin(); i != queuedObservers[e.m_type].end(); i++) + { + // Both object and callback function must be present + // Push to its queue, if it exists, otherwise remote observer + if (i->first != nullptr && i->second != nullptr) + { + i->first->eventQueue.push(Command(i->second, new T(e))); + } + else + { + i = queuedObservers[e.m_type].erase(i); + } + } + } + + /// + /// \brief Try to do an event from the priority queue + /// + void doEvent() + { + Command command; + if (eventQueue.try_pop(command)) + { + command.m_call(command.m_event); + delete command.m_event; + } + } + + /// + /// \brief Not thread safe, could run forever if events are constantly + /// being posted + /// \todo: need lock + /// + void doAllEvents() + { + while (!eventQueue.empty()) + { + doEvent(); + } + eventQueue.clear(); + } + + /// + /// \brief Pops all events and does the last one + /// + void doLastEvent() + { + Command command; + while (!eventQueue.empty()) + { + eventQueue.try_pop(command); + } + if (command.m_call != nullptr) + { + command.m_call(command.m_event); + delete command.m_event; + eventQueue.clear(); + } + } + +protected: + /// + /// \biref Constructor, object must be subclassed + /// + EventObject() = default; + +protected: + /// + /// \brief Removes all events from queue + /// cleans up copies of the event + /// + void clearEvents() + { + // Despite empty not being thread safe, it will + // still not be able to try_pop, which will only + // cause a short delay, whilst another thread is + // performing an push/pop from the queue + while (!eventQueue.empty()) + { + Command command; + if (eventQueue.try_pop(command)) + { + delete command.m_event; + } + } + eventQueue.clear(); + } + +public: + template<class T, class RecieverType> + friend void connect(EventObject*, EventType, RecieverType*, void (RecieverType::* func)(T*)); + template<typename T> + friend void connect(EventObject*, EventType, std::function<void(T*)>); + + template<typename T, class RecieverType> + friend void queueConnect(EventObject*, EventType, RecieverType*, void (RecieverType::* func)(T*)); + template<class T> + friend void queueConnect(EventObject*, EventType, EventObject*, std::function<void(T*)>); + + friend void disconnect(EventObject*, EventObject*, EventType); + +private: + tbb::concurrent_queue<Command> eventQueue; + //tbb::concurrent_priority_queue<Command> eventQueue; + tbb::concurrent_unordered_map<EventType, std::list<Observer>> queuedObservers; + tbb::concurrent_unordered_map<EventType, std::list<Observer>> directObservers; +}; + +#ifdef WIN32 +#pragma warning(push) +#pragma warning(disable: 4505) +#endif +/// +/// \brief Direct connection +/// When sender emits eventType, func will be called immediately/synchronously/within the same thread +/// Reciever function must be a member of reciever object +/// +template<class T, class RecieverType> +static void +connect(EventObject* sender, EventType eventType, + RecieverType* reciever, void (RecieverType::* func)(T*)) +{ + std::function<void(T*)> bindFunc = std::bind(func, reciever, std::placeholders::_1); + sender->directObservers[eventType].push_back(EventObject::Observer(nullptr, [ = ](Event* e) { bindFunc(static_cast<T*>(e)); })); +} + +template<class T, class RecieverType> +static void +connect(std::shared_ptr<EventObject> sender, EventType eventType, + std::shared_ptr<EventObject> reciever, void (RecieverType::* func)(T*)) +{ + connect<T>(sender.get(), eventType, reciever.get(), func); +} + +template<class T, class RecieverType> +static void +connect(std::shared_ptr<EventObject> sender, EventType eventType, + RecieverType* reciever, void (RecieverType::* func)(T*)) +{ + connect<T>(sender.get(), eventType, reciever, func); +} + +template<class T, class RecieverType> +static void +connect(EventObject* sender, EventType eventType, + std::shared_ptr<RecieverType> reciever, void (RecieverType::* func)(T*)) +{ + connect<T>(sender, eventType, reciever.get(), func); +} + +/// +/// \brief Direct connection (static, no object required) +/// When sender emits eventType, func will be called immediately/synchronously/within the same thread +/// +template<class T> +static void +connect(EventObject* sender, EventType eventType, + std::function<void(T*)> func) +{ + sender->directObservers[eventType].push_back(EventObject::Observer(nullptr, [ = ](Event* e) { func(static_cast<T*>(e)); })); +} + +template<class T> +static void +connect(std::shared_ptr<EventObject> sender, EventType eventType, + std::function<void(T*)> func) +{ + connect(sender.get(), eventType, func); +} + +/// +/// \brief Queued connection +/// When sender emits eventType, func will be queued to reciever in thread safe manner +/// Reciever function must be member of reciever object +/// +template<class T, class RecieverType> +static void +queueConnect(EventObject* sender, EventType type, RecieverType* reciever, void (RecieverType::* func)(T*)) +{ + // \todo Concept check that the function exists on reciever obj + std::function<void(T*)> bindFunc = std::bind(func, reciever, std::placeholders::_1); + sender->queuedObservers[type].push_back(EventObject::Observer(reciever, [ = ](Event* e) { bindFunc(static_cast<T*>(e)); })); +} + +template<class T, class RecieverType> +static void +queueConnect(std::shared_ptr<EventObject> sender, EventType type, std::shared_ptr<RecieverType> reciever, void (RecieverType::* func)(T*)) +{ + queueConnect<T>(sender.get(), type, reciever.get(), func); +} + +template<class T, class RecieverType> +static void +queueConnect(std::shared_ptr<EventObject> sender, EventType type, RecieverType* reciever, void (RecieverType::* func)(T*)) +{ + queueConnect<T>(sender.get(), type, reciever, func); +} + +template<class T, class RecieverType> +static void +queueConnect(EventObject* sender, EventType type, std::shared_ptr<RecieverType> reciever, void (RecieverType::* func)(T*)) +{ + queueConnect<T>(sender, type, reciever.get(), func); +} + +template<class T> +static void +queueConnect(EventObject* sender, EventType type, EventObject* reciever, std::function<void(T*)> func) +{ + sender->queuedObservers[type].push_back(EventObject::Observer(reciever, [ = ](Event* e) { func(static_cast<T*>(e)); })); +} + +template<class T> +static void +queueConnect(std::shared_ptr<EventObject> sender, EventType type, std::shared_ptr<EventObject> reciever, std::function<void(T*)> func) +{ + queueConnect(sender.get(), type, reciever.get(), func); +} + +template<class T> +static void +queueConnect(std::shared_ptr<EventObject> sender, EventType type, EventObject* reciever, std::function<void(T*)> func) +{ + queueConnect(sender.get(), type, reciever, func); +} + +template<class T> +static void +queueConnect(EventObject* sender, EventType type, std::shared_ptr<EventObject> reciever, std::function<void(T*)> func) +{ + queueConnect(sender, type, reciever.get(), func); +} + +/// +/// \brief Remove all connections of type +/// \todo: It is not possible to tell if a function pointer +/// is equal to another, without an using a handle, its impossible +/// to remove +/// +static void +disconnect(EventObject* sender, EventObject* reciever, EventType eventType) +{ + if (sender->queuedObservers.find(eventType) == sender->queuedObservers.end()) + { + return; + } + std::list<EventObject::Observer>::iterator i = + std::find_if(sender->queuedObservers[eventType].begin(), sender->queuedObservers[eventType].end(), + [&](const EventObject::Observer& observer) { return observer.first == reciever; }); + if (i != sender->queuedObservers[eventType].end()) + { + sender->queuedObservers[eventType].erase(i); + } +} + +static void +disconnect(std::shared_ptr<EventObject> sender, std::shared_ptr<EventObject> reciever, EventType eventType) +{ + disconnect(sender.get(), reciever.get(), eventType); +} + +static void +disconnect(std::shared_ptr<EventObject> sender, EventObject* reciever, EventType eventType) +{ + disconnect(sender.get(), reciever, eventType); +} + +static void +disconnect(EventObject* sender, std::shared_ptr<EventObject> reciever, EventType eventType) +{ + disconnect(sender, reciever.get(), eventType); +} + +#ifdef WIN32 +#pragma warning(pop) +#endif +} diff --git a/Source/Common/imstkLogger.cpp b/Source/Common/imstkLogger.cpp index f8fb8252a4a7648645293b1c02bd97cc20a17860..8722036efcf539d853db999c2709ce3de5b0f394 100644 --- a/Source/Common/imstkLogger.cpp +++ b/Source/Common/imstkLogger.cpp @@ -18,6 +18,7 @@ See the License for the specific language governing permissions and limitations under the License. =========================================================================*/ + #include "imstkLogger.h" #ifdef WIN32 diff --git a/Source/Common/imstkLogger.h b/Source/Common/imstkLogger.h index 3485c10d0c0f58bf8aec750a17ff75a05cf1960e..ff6778116bfd2f23bf8e8c031b3a27dfbd4772e0 100644 --- a/Source/Common/imstkLogger.h +++ b/Source/Common/imstkLogger.h @@ -20,12 +20,10 @@ limitations under the License. =========================================================================*/ #pragma once -#include "g3log/logmessage.hpp" -#include "g3log/logworker.hpp" - #include "imstkDataLogger.h" -#include <memory> +#include <g3log/logmessage.hpp> +#include <g3log/logworker.hpp> namespace imstk { @@ -77,7 +75,7 @@ class Logger { public: /// - /// \brief TODO + /// \brief Gets logger instances, creates if doesn't exist yet /// static Logger& getInstance() { @@ -92,6 +90,18 @@ public: return instance; } + /// + /// \brief Starts logger with default sinks, use getInstance to + /// create a logger with no sinks + /// + static Logger& startLogger() + { + Logger& logger = Logger::getInstance(); + logger.addFileSink("simulation"); + logger.addStdoutSink(); + return logger; + } + // Disable copy & move constructors & assignments Logger(const Logger&) = delete; Logger& operator=(const Logger&) = delete; @@ -107,7 +117,7 @@ public: /// /// \brief Add a sink that logs to file /// - std::unique_ptr<FileSinkHandle> addFileSink(const std::string& name, const std::string& path); + std::unique_ptr<FileSinkHandle> addFileSink(const std::string& name, const std::string& path = "./"); /// /// \brief Add your own sink diff --git a/Source/Common/imstkMath.h b/Source/Common/imstkMath.h index 14af78127ddb95a4eec4e365f949308e54166061..fed99309ed902ad6667757fc1ef7919b27b7f07a 100644 --- a/Source/Common/imstkMath.h +++ b/Source/Common/imstkMath.h @@ -25,10 +25,14 @@ #include <Eigen/Geometry> +#ifdef WIN32 #pragma warning( push ) #pragma warning( disable : 4127 ) +#endif #include <Eigen/Sparse> +#ifdef WIN32 #pragma warning( pop ) +#endif #include <Eigen/StdVector> #include <vector> @@ -61,12 +65,14 @@ using StdVectorOfVec4r = std::vector<Vec4r, Eigen::aligned_allocator<Vec4r>>; // 2D vector using Vec2f = Eigen::Vector2f; using Vec2d = Eigen::Vector2d; +using Vec2i = Eigen::Matrix<int, 2, 1>; using StdVectorOfVec2f = std::vector<Vec2f, Eigen::aligned_allocator<Vec2f>>; using StdVectorOfVec2d = std::vector<Vec2d, Eigen::aligned_allocator<Vec2d>>; // 3D vector using Vec3f = Eigen::Vector3f; using Vec3d = Eigen::Vector3d; +using Vec3i = Eigen::Matrix<int, 3, 1>; using StdVectorOfVec3f = std::vector<Vec3f, Eigen::aligned_allocator<Vec3f>>; using StdVectorOfVec3d = std::vector<Vec3d, Eigen::aligned_allocator<Vec3d>>; @@ -76,6 +82,10 @@ using Vec4d = Eigen::Vector4d; using StdVectorOfVec4f = std::vector<Vec4f, Eigen::aligned_allocator<Vec4f>>; using StdVectorOfVec4d = std::vector<Vec4d, Eigen::aligned_allocator<Vec4d>>; +// 6D vector +using Vec6f = Eigen::Matrix<float, 6, 1>; +using Vec6d = Eigen::Matrix<double, 6, 1>; + // Dynamic size vector using Vectorf = Eigen::VectorXf; using Vectord = Eigen::VectorXd; @@ -83,8 +93,10 @@ using StdVectorOfVectorf = std::vector<Vectorf, Eigen::aligned_allocator<Vectorf using StdVectorOfVectord = std::vector<Vectord, Eigen::aligned_allocator<Vectord>>; // Quaternion -using Quatf = Eigen::Quaternion<float, Eigen::DontAlign>; -using Quatd = Eigen::Quaternion<double, Eigen::DontAlign>; +using Quatf = Eigen::Quaternion<float>; +using Quatd = Eigen::Quaternion<double>; +using StdVectorOfQuatf = std::vector<Quatf, Eigen::aligned_allocator<Quatf>>; +using StdVectorOfQuatd = std::vector<Quatd, Eigen::aligned_allocator<Quatd>>; // Angle-Axis using Rotf = Eigen::AngleAxisf; @@ -93,6 +105,7 @@ using Rotd = Eigen::AngleAxisd; // 3x3 Matrix using Mat3f = Eigen::Matrix3f; using Mat3d = Eigen::Matrix3d; +using StdVectorOfMat3d = std::vector<Mat3d, Eigen::aligned_allocator<Mat3d>>; // 4x4 Matrix using Mat4f = Eigen::Matrix4f; @@ -153,4 +166,4 @@ using AffineTransform3d = Eigen::Affine3d; #define MAX_F std::numeric_limits<float>::max() #define MIN_F std::numeric_limits<float>::min() #define VERY_SMALL_EPSILON_F std::numeric_limits<float>::epsilon() -} // end namespace imstk +} diff --git a/Source/Common/imstkModule.cpp b/Source/Common/imstkModule.cpp deleted file mode 100644 index fc5fe70333c4d3e981777539f1d2834351f40fdc..0000000000000000000000000000000000000000 --- a/Source/Common/imstkModule.cpp +++ /dev/null @@ -1,263 +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 "imstkModule.h" -#include "imstkMath.h" -#include "imstkTimer.h" - -namespace imstk -{ -Module::Module(const std::string& name, int loopDelay /*= 0*/) : - m_name(name), - m_frameCounter(std::make_shared<UPSCounter>()), - m_trackFPS(false), - m_loopDelay(loopDelay) -{ -} - -void -Module::start() -{ - if (m_status != ModuleStatus::Inactive) - { - LOG(WARNING) << "Can not start '" << m_name << "'.\n" - << "Module already/still active."; - return; - } - - // Init - m_status = ModuleStatus::Starting; - if (m_preInitCallback) - { - m_preInitCallback(this); - } - - this->initModule(); - - if (m_postInitCallback) - { - m_postInitCallback(this); - } - - m_status = ModuleStatus::Running; - - // Keep active, wait for terminating call - std::chrono::steady_clock::time_point previous_t = std::chrono::steady_clock::now() - std::chrono::minutes(1); - std::chrono::steady_clock::time_point current_t; - long long elapsed; - while (m_status != ModuleStatus::Terminating) - { - if (m_status == ModuleStatus::Pausing) - { - m_status = ModuleStatus::Paused; - } - else if (m_status == ModuleStatus::Running) - { - // Short path to run module if loop delay = 0 - // (updating as fast as possible) - if (m_loopDelay < VERY_SMALL_EPSILON_D) - { - if (m_trackFPS) - { - m_frameCounter->setStartPointOfUpdate(); - } - - if (m_preUpdateCallback) - { - m_preUpdateCallback(this); - } - this->runModule(); - if (m_postUpdateCallback) - { - m_postUpdateCallback(this); - } - - if (m_trackFPS) - { - m_frameCounter->setEndPointOfUpdate(); - - std::cout << "\r" << this->getName() << " running at " - << m_frameCounter->getUPS() << " ups " << std::flush; - } - continue; - } - - // If forcing a frequency, wait until enough time elapsed - current_t = std::chrono::steady_clock::now(); - elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(current_t - previous_t).count(); - if (elapsed >= m_loopDelay) - { - if (m_trackFPS) - { - m_frameCounter->setStartPointOfUpdate(); - } - - if (m_preUpdateCallback) - { - m_preUpdateCallback(this); - } - this->runModule(); - if (m_postUpdateCallback) - { - m_postUpdateCallback(this); - } - - if (m_trackFPS) - { - m_frameCounter->setEndPointOfUpdate(); - } - - previous_t = current_t; - } - } - } - - m_status = ModuleStatus::Inactive; -} - -void -Module::run() -{ - if (m_status != ModuleStatus::Paused) - { - return; - } - - m_status = ModuleStatus::Running; -} - -void -Module::pause() -{ - if (m_status == ModuleStatus::Running) - { - m_status = ModuleStatus::Pausing; - - while (m_status != ModuleStatus::Paused) {} - } -} - -void -Module::end() -{ - // Cleanup - if (m_preCleanUpCallback) - { - m_preCleanUpCallback(this); - } - - this->cleanUpModule(); - - if (m_postCleanUpCallback) - { - m_postCleanUpCallback(this); - } - - if ((m_status == ModuleStatus::Inactive) - || (m_status == ModuleStatus::Terminating)) - { - LOG(WARNING) << "Can not end '" << m_name << "'.\n" - << "Module already inactive or terminating."; - return; - } - - m_status = ModuleStatus::Terminating; - - while (m_status != ModuleStatus::Inactive) {} -} - -ModuleStatus -Module::getStatus() const -{ - return m_status.load(); -} - -const std::string& -Module::getName() const -{ - return m_name; -} - -double -Module::getLoopDelay() const -{ - return m_loopDelay; -} - -void -Module::setLoopDelay(const double milliseconds) -{ - if (milliseconds < 0) - { - LOG(WARNING) << "Module::setLoopDelay error: delay must be positive."; - return; - } - m_loopDelay = milliseconds; -} - -double -Module::getFrequency() const -{ - if (m_loopDelay < VERY_SMALL_EPSILON_D) - { - LOG(WARNING) << "Module::getFrequency warning: loop delay is set to 0ms, " - << "therefore not regulated by a frequency. Returning 0."; - return 0; - } - return 1000.0 / m_loopDelay; -} - -void -Module::setFrequency(const double f) -{ - if (f < 0) - { - LOG(WARNING) << "Module::setFrequency error: f must be positive, " - << "or equal to 0 to run the module in a closed loop."; - return; - } - if (f < VERY_SMALL_EPSILON_D) - { - m_loopDelay = 0; - return; - } - m_loopDelay = 1000.0 / f; -} - -unsigned int -Module::getUPS() -{ - if (m_status != ModuleStatus::Running) - { - return 0; - } - - if (m_trackFPS) - { - return m_frameCounter->getUPS(); - } - else - { - LOG(WARNING) << "Frame counter is not enabled!"; - return 0; - } -} -} diff --git a/Source/Common/imstkModule.h b/Source/Common/imstkModule.h deleted file mode 100644 index 9344e78233746276285089187cbea69fff6cb921..0000000000000000000000000000000000000000 --- a/Source/Common/imstkModule.h +++ /dev/null @@ -1,177 +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. - -=========================================================================*/ - -#pragma once - -#include <iostream> -#include <atomic> -#include <functional> -#include <memory> - -namespace imstk -{ -class UPSCounter; - -/// -/// \brief Enumerations for the status of the module -/// -enum class ModuleStatus -{ - Starting, - Running, - Pausing, - Paused, - Terminating, - Inactive -}; - -/// -/// \class Module -/// -/// \brief iMSTK module -/// -class Module -{ -using CallbackFunction = std::function<void (Module* module)>; - -public: - /// - /// \brief Constructor - /// - Module(const std::string& name, int loopDelay = 0); - - /// - /// \brief Destructor - /// - virtual ~Module() = default; - - /// - /// \brief Start the module - /// - void start(); - - /// - /// \brief Run module - /// - void run(); - - /// - /// \brief Pause the module - /// - void pause(); - - /// - /// \brief End the module - /// - void end(); - - /// - /// \brief Set callback function for initialization - /// - inline void setPreInitCallback(CallbackFunction foo) { m_preInitCallback = foo; } - inline void setPostInitCallback(CallbackFunction foo) { m_postInitCallback = foo; } - /// - /// \brief Set callback function for update - /// - inline void setPreUpdateCallback(CallbackFunction foo) { m_preUpdateCallback = foo; } - inline void setPostUpdateCallback(CallbackFunction foo) { m_postUpdateCallback = foo; } - /// - /// \brief Set callback function for cleanup - /// - inline void setPreCleanUpCallback(CallbackFunction foo) { m_preCleanUpCallback = foo; } - inline void setPostCleanUpCallback(CallbackFunction foo) { m_postCleanUpCallback = foo; } - - /// - /// \brief Get the status of the module - /// - ModuleStatus getStatus() const; - - /// - /// \brief Get the name of the module - /// - const std::string& getName() const; - - /// - /// \brief Get loop delay - /// - double getLoopDelay() const; - - /// - /// \brief Set the loop delay - /// - void setLoopDelay(const double milliseconds); - - /// - /// \brief Get loop delay - /// - double getFrequency() const; - - /// - /// \brief Set the loop delay - /// - void setFrequency(const double f); - - /// - /// \brief Enable frame count - /// - void enableFrameCount() { m_trackFPS = true; }; - /// - /// \brief Disable frame count - /// - void disableFrameCount() { m_trackFPS = false; }; - - /// \return true is frame count is already enabled - bool isFrameCountEnabled() const { return m_trackFPS; }; - - unsigned int getUPS(); - -protected: - - /// - /// \brief Initialize module - /// - virtual void initModule() = 0; - - /// - /// \brief Run the module - /// - virtual void runModule() = 0; - - /// - /// \brief Clean the module - /// - virtual void cleanUpModule() = 0; - - CallbackFunction m_preInitCallback; ///> function callback preceding module initialization - CallbackFunction m_postInitCallback; ///> function callback following module initialization - CallbackFunction m_preUpdateCallback; ///> function callback preceding module update - CallbackFunction m_postUpdateCallback; ///> function callback following module update - CallbackFunction m_preCleanUpCallback; ///> function callback preceding module cleanup - CallbackFunction m_postCleanUpCallback; ///> function callback following module cleanup - - std::atomic<ModuleStatus> m_status { ModuleStatus::Inactive }; ///> Module status - std::shared_ptr<UPSCounter> m_frameCounter; - - std::string m_name; ///> Name of the module - double m_loopDelay; ///> Loop delay - bool m_trackFPS; ///> Flag to enable/diable FPS tracking -}; -} diff --git a/Source/Common/imstkNew.h b/Source/Common/imstkNew.h new file mode 100644 index 0000000000000000000000000000000000000000..e9b7d218bb80e981ef811d191786e9624ca5619b --- /dev/null +++ b/Source/Common/imstkNew.h @@ -0,0 +1,94 @@ +/*========================================================================= + +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 <memory> + +namespace imstk +{ +//template<typename T> +//using imstkSmartPtr = std::shared_ptr<T>; +// +//template<typename T> +//using imstkWeakPtr = std::weak_ptr<T>; +// +//template<typename T> +//using imstkUniquePtr = std::unique_ptr<T>; + +/// +/// \class imstkNew +/// +/// \brief std::shared_ptr<T> obj = std::make_shared<T>(); equivalent, convenience class +/// for STL shared allocations. Cannot be used in overloaded polymorphic calls +/// +template<class T> +class imstkNew +{ +public: + template<typename U> + friend class imstkNew; + +public: + imstkNew() : object(std::make_shared<T>()) { } + + template<typename ... Args> + explicit imstkNew(Args&&... args) : object(std::make_shared<T>(std::forward<Args>(args)...)) { } + + // Move, reference to old is removed + imstkNew(imstkNew&& obj) : object(obj.object) { obj.object = nullptr; } + +public: + T* operator->() const { return object.get(); } + T& operator*() const { return *static_cast<T*>(object); } + + /// + /// \brief Returns the raw pointer + /// + T* getPtr() const { return object.get(); } + + /// + /// \brief Returns const ref to STL smart pointer + /// + const std::shared_ptr<T>& get() const { return object; } + + /// + /// \brief Implicit conversion + /// + operator std::shared_ptr<T>() const { return object; } + + /// + /// \brief Hack for multiple implicit conversions, does not work with overloads though + /// as it won't know what to cast too + /// + template<typename U> + operator std::shared_ptr<U>() const + { + static_assert(std::is_base_of<U, T>::value, "Argument U type not compatible with imstkNew<T>'s T"); + return std::dynamic_pointer_cast<U>(object); + } + +private: + imstkNew(const imstkNew<T>&) = delete; + void operator=(const imstkNew<T>&) = delete; + std::shared_ptr<T> object; +}; +} \ No newline at end of file diff --git a/Source/Common/imstkTypes.h b/Source/Common/imstkTypes.h new file mode 100644 index 0000000000000000000000000000000000000000..5c318dbd544c9244790c3d1e7498d2a1ad07971c --- /dev/null +++ b/Source/Common/imstkTypes.h @@ -0,0 +1,108 @@ +/*========================================================================= + + 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 <limits> + +namespace imstk +{ +using ScalarType = unsigned char; +#define IMSTK_VOID 0 +#define IMSTK_CHAR 1 +#define IMSTK_UNSIGNED_CHAR 2 +#define IMSTK_SHORT 3 +#define IMSTK_UNSIGNED_SHORT 4 +#define IMSTK_INT 5 +#define IMSTK_UNSIGNED_INT 6 +#define IMSTK_LONG 7 +#define IMSTK_UNSIGNED_LONG 8 +#define IMSTK_FLOAT 9 +#define IMSTK_DOUBLE 10 +#define IMSTK_LONG_LONG 11 +#define IMSTK_UNSIGNED_LONG_LONG 12 + +#define IMSTK_CHAR_MAX std::numeric_limits<char>::max(); +#define IMSTK_CHAR_MIN std::numeric_limits<char>::min(); +#define IMSTK_UNSIGNED_CHAR_MAX std::numeric_limits<unsigned char>::max(); +#define IMSTK_UNSIGNED_CHAR_MIN std::numeric_limits<unsigned char>::min(); +#define IMSTK_SHORT_MAX std::numeric_limits<short>::max(); +#define IMSTK_SHORT_MIN std::numeric_limits<short>::min(); +#define IMSTK_UNSIGNED_SHORT_MAX std::numeric_limits<unsigned short>::max(); +#define IMSTK_UNSIGNED_SHORT_MIN std::numeric_limits<unsigned short>::min(); +#define IMSTK_INT_MAX std::numeric_limits<int>::max(); +#define IMSTK_INT_MIN std::numeric_limits<int>::min(); +#define IMSTK_UNSIGNED_INT_MAX std::numeric_limits<unsigned int>::max(); +#define IMSTK_UNSIGNED_INT_MIN std::numeric_limits<unsigned int>::min(); +#define IMSTK_LONG_MAX std::numeric_limits<long>::max(); +#define IMSTK_LONG_MIN std::numeric_limits<long>::min(); +#define IMSTK_UNSIGNED_LONG_MAX std::numeric_limits<unsigned long>::max(); +#define IMSTK_UNSIGNED_LONG_MIN std::numeric_limits<unsigned long>::min(); +#define IMSTK_FLOAT_MAX std::numeric_limits<float>::max(); +#define IMSTK_FLOAT_MIN std::numeric_limits<float>::min(); +#define IMSTK_DOUBLE_MAX std::numeric_limits<double>::max(); +#define IMSTK_DOUBLE_MIN std::numeric_limits<double>::min(); +#define IMSTK_LONG_LONG_MAX std::numeric_limits<long>::max(); +#define IMSTK_LONG_LONG_MIN std::numeric_limits<long>::min(); +#define IMSTK_UNSIGNED_LONG_LONG_MAX std::numeric_limits<unsigned long long>::max(); +#define IMSTK_UNSIGNED_LONG_LONG_MIN std::numeric_limits<unsigned long long>::min(); + +/// +/// \brief Used to quiet compiler warnings of parameters not used +/// +#define imstkNotUsed(x) + +// todo: Switch to template type lists +/// +/// \brief Maps ScalarType type to templated function call +/// +#define TemplateMacroCase(typeN, type, call) \ +case typeN: { using IMSTK_TT = type; call; }; break +#define TemplateMacro(call) \ + TemplateMacroCase(IMSTK_CHAR, char, call); \ + TemplateMacroCase(IMSTK_UNSIGNED_CHAR, unsigned char, call); \ + TemplateMacroCase(IMSTK_SHORT, short, call); \ + TemplateMacroCase(IMSTK_UNSIGNED_SHORT, unsigned short, call); \ + TemplateMacroCase(IMSTK_INT, int, call); \ + TemplateMacroCase(IMSTK_UNSIGNED_INT, unsigned int, call); \ + TemplateMacroCase(IMSTK_LONG, long, call); \ + TemplateMacroCase(IMSTK_UNSIGNED_LONG, unsigned long, call); \ + TemplateMacroCase(IMSTK_FLOAT, float, call); \ + TemplateMacroCase(IMSTK_DOUBLE, double, call); \ + TemplateMacroCase(IMSTK_LONG_LONG, long long, call); \ + TemplateMacroCase(IMSTK_UNSIGNED_LONG_LONG, unsigned long long, call) + +/// +/// \brief Returns scalar type given template +/// +#define TypeTemplateMacro(templateType) \ + (std::is_same<templateType, char>::value ? IMSTK_CHAR : \ + (std::is_same<templateType, unsigned char>::value ? IMSTK_UNSIGNED_CHAR : \ + (std::is_same<templateType, short>::value ? IMSTK_SHORT : \ + (std::is_same<templateType, unsigned short>::value ? IMSTK_UNSIGNED_SHORT : \ + (std::is_same<templateType, int>::value ? IMSTK_INT : \ + (std::is_same<templateType, unsigned int>::value ? IMSTK_UNSIGNED_INT : \ + (std::is_same<templateType, long>::value ? IMSTK_LONG : \ + (std::is_same<templateType, unsigned long>::value ? IMSTK_UNSIGNED_LONG : \ + (std::is_same<templateType, float>::value ? IMSTK_FLOAT : \ + (std::is_same<templateType, double>::value ? IMSTK_DOUBLE : \ + (std::is_same<templateType, long long>::value ? IMSTK_LONG_LONG : \ + (std::is_same<templateType, unsigned long long>::value ? IMSTK_UNSIGNED_LONG_LONG : 0)))))))))))) +} \ No newline at end of file diff --git a/Source/Constraint/CMakeLists.txt b/Source/Constraint/CMakeLists.txt index df474dc4b0d6e0c0fc3f540bd351fe3b70751061..145b374948d7e8e88e1004899dbc27a4e1e08044 100644 --- a/Source/Constraint/CMakeLists.txt +++ b/Source/Constraint/CMakeLists.txt @@ -5,6 +5,7 @@ include(imstkAddLibrary) imstk_add_library( Constraints SUBDIR_LIST PbdConstraints + RigidBodyConstraints DEPENDS Common DataStructures diff --git a/Source/Constraint/PbdConstraints/imstkPbdAreaConstraint.cpp b/Source/Constraint/PbdConstraints/imstkPbdAreaConstraint.cpp index 6121b15e54634b7d15e52f26976341c327a21ed0..13482122b63ac5c6a098d8f4dc75041a48f748bc 100644 --- a/Source/Constraint/PbdConstraints/imstkPbdAreaConstraint.cpp +++ b/Source/Constraint/PbdConstraints/imstkPbdAreaConstraint.cpp @@ -72,6 +72,7 @@ PbdAreaConstraint::computeValueAndGradient(const StdVectorOfVec3d& currVertexPos n /= 2 * c; c -= m_restArea; + dcdx.resize(3); dcdx[0] = e1.cross(n); dcdx[1] = e2.cross(n); dcdx[2] = e0.cross(n); diff --git a/Source/Constraint/PbdConstraints/imstkPbdCollisionConstraint.cpp b/Source/Constraint/PbdConstraints/imstkPbdCollisionConstraint.cpp index dda274ce9101a8d8b14404fd0ee0bd6062378fa5..0cb65d8171b08cce21c41de5a9a6d5bc71dcb009 100644 --- a/Source/Constraint/PbdConstraints/imstkPbdCollisionConstraint.cpp +++ b/Source/Constraint/PbdConstraints/imstkPbdCollisionConstraint.cpp @@ -20,7 +20,6 @@ =========================================================================*/ #include "imstkPbdCollisionConstraint.h" -#include "imstkLogger.h" namespace imstk { diff --git a/Source/Constraint/PbdConstraints/imstkPbdConstantDensityConstraint.cpp b/Source/Constraint/PbdConstraints/imstkPbdConstantDensityConstraint.cpp index 03fe3fd841019825d024481ad38f58ffb441640d..114d976944b4e4e059688dfc2cec88301965a4d5 100644 --- a/Source/Constraint/PbdConstraints/imstkPbdConstantDensityConstraint.cpp +++ b/Source/Constraint/PbdConstraints/imstkPbdConstantDensityConstraint.cpp @@ -45,9 +45,9 @@ PbdConstantDensityConstraint::initConstraint(const StdVectorOfVec3d& initVertexP } void -PbdConstantDensityConstraint::projectConstraint(const StdVectorOfReal& currInvMasses, - const double dt, - const PbdConstraint::SolverType& type, +PbdConstantDensityConstraint::projectConstraint(const StdVectorOfReal& imstkNotUsed(currInvMasses), + const double imstkNotUsed(dt), + const PbdConstraint::SolverType& imstkNotUsed(type), StdVectorOfVec3d& currVertexPositions) { const size_t numParticles = currVertexPositions.size(); diff --git a/Source/Constraint/PbdConstraints/imstkPbdConstantDensityConstraint.h b/Source/Constraint/PbdConstraints/imstkPbdConstantDensityConstraint.h index 81f97b656f2a54f98b8c07ad9640af60e30f50e6..4c29262340b0d0791c2511f9a6085e3b13a7b8c6 100644 --- a/Source/Constraint/PbdConstraints/imstkPbdConstantDensityConstraint.h +++ b/Source/Constraint/PbdConstraints/imstkPbdConstantDensityConstraint.h @@ -21,8 +21,9 @@ limitations under the License. #pragma once -#include "imstkPbdConstraint.h" #include "imstkNeighborSearch.h" +#include "imstkPbdConstraint.h" +#include "imstkTypes.h" namespace imstk { @@ -64,9 +65,9 @@ public: const PbdConstraint::SolverType& type, StdVectorOfVec3d& currVertexPositions) override; - bool computeValueAndGradient(const StdVectorOfVec3d& currVertexPositions, - double& c, - StdVectorOfVec3d& dcdx) const + bool computeValueAndGradient(const StdVectorOfVec3d& imstkNotUsed(currVertexPositions), + double& imstkNotUsed(c), + StdVectorOfVec3d& imstkNotUsed(dcdx)) const { return true; } diff --git a/Source/Constraint/PbdConstraints/imstkPbdDihedralConstraint.cpp b/Source/Constraint/PbdConstraints/imstkPbdDihedralConstraint.cpp index d45e2edd87341aa2e7d24fe589cef5e3411168b4..574faf11b83be874be4f5b1fb3cecfeaa593cece 100644 --- a/Source/Constraint/PbdConstraints/imstkPbdDihedralConstraint.cpp +++ b/Source/Constraint/PbdConstraints/imstkPbdDihedralConstraint.cpp @@ -20,7 +20,6 @@ =========================================================================*/ #include "imstkPbdDihedralConstraint.h" -#include <iostream> namespace imstk { diff --git a/Source/Constraint/PbdConstraints/imstkPbdEdgeEdgeCollisionConstraint.cpp b/Source/Constraint/PbdConstraints/imstkPbdEdgeEdgeCollisionConstraint.cpp index 85986e9963e3690f7977c2f6e1854dd387c8b30f..5845b7f6a81c4db4c17b5367da6370b55f2e8b17 100644 --- a/Source/Constraint/PbdConstraints/imstkPbdEdgeEdgeCollisionConstraint.cpp +++ b/Source/Constraint/PbdConstraints/imstkPbdEdgeEdgeCollisionConstraint.cpp @@ -20,7 +20,6 @@ =========================================================================*/ #include "imstkPbdEdgeEdgeCollisionConstraint.h" -#include "imstkLogger.h" namespace imstk { diff --git a/Source/Constraint/PbdConstraints/imstkPbdFETetConstraint.cpp b/Source/Constraint/PbdConstraints/imstkPbdFETetConstraint.cpp index 4763b2f29c6d5d94db7561aec5eac5eb262a230d..50ba72fd421ea887e597d1fdaece5dd0b4a329cd 100644 --- a/Source/Constraint/PbdConstraints/imstkPbdFETetConstraint.cpp +++ b/Source/Constraint/PbdConstraints/imstkPbdFETetConstraint.cpp @@ -20,8 +20,6 @@ =========================================================================*/ #include "imstkPbdFETetConstraint.h" -#include "imstkLogger.h" -#include <iostream> namespace imstk { @@ -166,13 +164,9 @@ PbdFEMTetConstraint::computeValueAndGradient(const StdVectorOfVec3d& currVertexP { break; } - default: - { - LOG(FATAL) << "Material type not supported ! \n"; break; } - } Mat3d gradC = m_elementVolume * P * m_invRestMat.transpose(); cval = C; diff --git a/Source/Constraint/PbdConstraints/imstkPbdPointTriCollisionConstraint.cpp b/Source/Constraint/PbdConstraints/imstkPbdPointTriCollisionConstraint.cpp index 75b13a8d9e49a1a6ab776c8a3cd7b9e55464758a..2db3daa961a5a078f899c49b3b48e30646b0d09e 100644 --- a/Source/Constraint/PbdConstraints/imstkPbdPointTriCollisionConstraint.cpp +++ b/Source/Constraint/PbdConstraints/imstkPbdPointTriCollisionConstraint.cpp @@ -21,8 +21,6 @@ #include "imstkPbdPointTriCollisionConstraint.h" -#include "imstkLogger.h" - namespace imstk { void diff --git a/Source/Constraint/RigidBodyConstraints/imstkRbdConstraint.cpp b/Source/Constraint/RigidBodyConstraints/imstkRbdConstraint.cpp new file mode 100644 index 0000000000000000000000000000000000000000..218dae0e4bda4b7b1e6920ec469a9f377fbee6b1 --- /dev/null +++ b/Source/Constraint/RigidBodyConstraints/imstkRbdConstraint.cpp @@ -0,0 +1,59 @@ +/*========================================================================= + + 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 "imstkRbdConstraint.h" +#include "imstkPointSet.h" + +namespace imstk +{ +namespace expiremental +{ +void +RigidBody::setInertiaFromPointSet(std::shared_ptr<PointSet> pointset, const double scale, const bool useBoundingBoxOrigin) +{ + Mat3d results; + results.setZero(); + + Vec3d centroid = Vec3d(0.0, 0.0, 0.0); + if (useBoundingBoxOrigin) + { + Vec3d min, max; + pointset->computeBoundingBox(min, max); + centroid = (min + max) * 0.5; + } + const StdVectorOfVec3d& vertices = pointset->getVertexPositions(Geometry::DataType::PreTransform); + for (size_t i = 0; i < vertices.size(); i++) + { + const Vec3d r = vertices[i] - centroid; + results(0, 0) += r[1] * r[1] + r[2] * r[2]; + results(1, 1) += r[0] * r[0] + r[2] * r[2]; + results(2, 2) += r[0] * r[0] + r[1] * r[1]; + results(1, 0) += -r[0] * r[1]; + results(2, 0) += -r[0] * r[2]; + results(2, 1) += -r[1] * r[2]; + } + results(0, 2) = results(2, 0); + results(0, 1) = results(1, 0); + results(1, 2) = results(2, 1); + m_intertiaTensor = results * m_mass * scale; +} +} +} \ No newline at end of file diff --git a/Source/Constraint/RigidBodyConstraints/imstkRbdConstraint.h b/Source/Constraint/RigidBodyConstraints/imstkRbdConstraint.h new file mode 100644 index 0000000000000000000000000000000000000000..a4728e0d94be95fca3a0372c33057b3f0c980532 --- /dev/null +++ b/Source/Constraint/RigidBodyConstraints/imstkRbdConstraint.h @@ -0,0 +1,118 @@ +/*========================================================================= + + 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 "imstkMath.h" + +#include <memory> + +namespace imstk +{ +class PointSet; + +namespace expiremental +{ +/// +/// \brief Serves as a handle to the body +/// +struct RigidBody +{ + public: + double m_mass; + Mat3d m_intertiaTensor; + Vec3d m_initPos = Vec3d(0.0, 0.0, 0.0); + Quatd m_initOrientation = Quatd(1.0, 0.0, 0.0, 0.0); + Vec3d m_initVelocity; + Vec3d m_initAngularVelocity; + Vec3d m_initForce; + Vec3d m_initTorque; + bool m_isStatic; + + // Vec3d m_externalForce; + //RigidBodyState2* m_state; // A RigidBody can only belong to one state + Vec3d* m_pos; + Quatd* m_orientation; + Vec3d* m_velocity; + Vec3d* m_angularVelocity; + Vec3d* m_force; + Vec3d* m_torque; + + const Vec3d& getPosition() const { return *m_pos; } + const Quatd& getOrientation() const { return *m_orientation; } + const Vec3d& getVelocity() const { return *m_velocity; } + const Vec3d& getAngularVelocity() const { return *m_angularVelocity; } + const Vec3d& getForce() const { return *m_force; } + const Vec3d& getTorque() const { return *m_torque; } + + /// + /// \brief Convience function to set the inertia tensor based off provided geometry + /// assuming uniform mass at each point. + /// + void setInertiaFromPointSet(std::shared_ptr<PointSet> pointset, const double scale = 1.0, const bool useBoundingBoxOrigin = true); +}; + +/// +/// \class RbdConstraint +/// +/// \brief Abstract class for rigid body constraints +/// \todo: consider removing static flags and using sides in the interaction +/// +class RbdConstraint +{ +public: + enum class Side + { + A, + B, + AB + }; + +protected: + RbdConstraint(std::shared_ptr<RigidBody> rbd1, + std::shared_ptr<RigidBody> rbd2, const Side side) : + m_obj1(rbd1), m_obj2(rbd2), m_side(side) + { + } + +public: + virtual ~RbdConstraint() = default; + +public: + /// + /// \brief Compute constraint jacobian + /// + virtual void compute(double dt) = 0; + +public: + // Jacobian + Eigen::Matrix<double, 3, 4> J = Eigen::Matrix<double, 3, 4>::Zero(); + double vu = 0.0; + double range[2] = { 0.0, std::numeric_limits<double>::max() }; + + // Objects involved + std::shared_ptr<RigidBody> m_obj1 = nullptr; + std::shared_ptr<RigidBody> m_obj2 = nullptr; + + Side m_side = Side::AB; +}; +} +} \ No newline at end of file diff --git a/Source/Constraint/RigidBodyConstraints/imstkRbdContactConstraint.cpp b/Source/Constraint/RigidBodyConstraints/imstkRbdContactConstraint.cpp new file mode 100644 index 0000000000000000000000000000000000000000..045184d886863276a4d3c48656ff7e7e9f3116f8 --- /dev/null +++ b/Source/Constraint/RigidBodyConstraints/imstkRbdContactConstraint.cpp @@ -0,0 +1,55 @@ +/*========================================================================= + + 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 "imstkRbdContactConstraint.h" + +namespace imstk +{ +namespace expiremental +{ +void +RbdContactConstraint::compute(double dt) +{ + // Jacobian of contact + J = Eigen::Matrix<double, 3, 4>::Zero(); + if ((m_side == Side::AB || m_side == Side::A) && !m_obj1->m_isStatic) + { + // Displacement from center of mass + const Vec3d r1 = m_contactPt - m_obj1->getPosition(); + const Vec3d c = r1.cross(-m_contactN); + J(0, 0) = -m_contactN[0]; J(0, 1) = c[0]; + J(1, 0) = -m_contactN[1]; J(1, 1) = c[1]; + J(2, 0) = -m_contactN[2]; J(2, 1) = c[2]; + } + if ((m_side == Side::AB || m_side == Side::B) && !m_obj2->m_isStatic) + { + // Displacement from center of mass + const Vec3d r2 = m_contactPt - m_obj2->getPosition(); + const Vec3d c = r2.cross(m_contactN); + J(0, 2) = m_contactN[0]; J(0, 3) = c[0]; + J(1, 2) = m_contactN[1]; J(1, 3) = c[1]; + J(2, 2) = m_contactN[2]; J(2, 3) = c[2]; + } + + vu = m_contactDepth * m_beta / dt; +} +} +}; \ No newline at end of file diff --git a/Source/Constraint/RigidBodyConstraints/imstkRbdContactConstraint.h b/Source/Constraint/RigidBodyConstraints/imstkRbdContactConstraint.h new file mode 100644 index 0000000000000000000000000000000000000000..6d295ebd1503f6df20fbb55c822dc33e32d7760e --- /dev/null +++ b/Source/Constraint/RigidBodyConstraints/imstkRbdContactConstraint.h @@ -0,0 +1,65 @@ +/*========================================================================= + + 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 "imstkRbdConstraint.h" + +#include <functional> + +namespace imstk +{ +namespace expiremental +{ +/// +/// \class RbdContactConstraint +/// +/// \brief A hard rigid body constraint to prevent intersection +/// +class RbdContactConstraint : public RbdConstraint +{ +public: + RbdContactConstraint( + std::shared_ptr<RigidBody> obj1, + std::shared_ptr<RigidBody> obj2, + const Vec3d& contactN, + const Vec3d& contactPt, + const double contactDepth, + const double beta = 0.05, + const Side side = Side::AB) : RbdConstraint(obj1, obj2, side), + m_contactN(contactN), m_contactPt(contactPt), + m_contactDepth(contactDepth), m_beta(beta) + { + } + + ~RbdContactConstraint() override = default; + +public: + void compute(double dt) override; + +private: + Vec3d m_contactPt; + Vec3d m_contactN; + double m_contactDepth; + double m_beta = 0.05; +}; +} +} \ No newline at end of file diff --git a/Source/Constraint/RigidBodyConstraints/imstkRbdDistanceConstraint.cpp b/Source/Constraint/RigidBodyConstraints/imstkRbdDistanceConstraint.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6595d69ad7ad6264bb4c990af5b7441b33e3d536 --- /dev/null +++ b/Source/Constraint/RigidBodyConstraints/imstkRbdDistanceConstraint.cpp @@ -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. + +=========================================================================*/ + +#include "imstkRbdDistanceConstraint.h" +#include "imstkTypes.h" + +namespace imstk +{ +namespace expiremental +{ +RbdDistanceConstraint::RbdDistanceConstraint( + std::shared_ptr<RigidBody> obj1, + std::shared_ptr<RigidBody> obj2, + const Vec3d& p1, const Vec3d& p2, + double dist, + const Side side) : RbdConstraint(obj1, obj2, side), + m_p1(p1), m_p2(p2), m_dist(dist) +{ +} + +void +RbdDistanceConstraint::compute(double imstkNotUsed(dt)) +{ + J = Eigen::Matrix<double, 3, 4>::Zero(); + if ((m_side == Side::AB || m_side == Side::A) && !m_obj1->m_isStatic) + { + // Displacement from center of mass + const Vec3d r1 = m_p1 - m_obj1->getPosition(); + const Vec3d diff = m_p2 - m_p1; + const Vec3d c = r1.cross(diff); + J(0, 0) = -diff[0]; J(0, 1) = -c[0]; + J(1, 0) = -diff[1]; J(1, 1) = -c[1]; + J(2, 0) = -diff[2]; J(2, 1) = -c[2]; + } + if ((m_side == Side::AB || m_side == Side::B) && !m_obj2->m_isStatic) + { + const Vec3d r2 = m_p2 - m_obj2->getPosition(); + const Vec3d diff = m_p2 - m_p1; + const Vec3d c = r2.cross(diff); + J(0, 0) = diff[0]; J(0, 1) = c[0]; + J(1, 0) = diff[1]; J(1, 1) = c[1]; + J(2, 0) = diff[2]; J(2, 1) = c[2]; + } +} +} +} \ No newline at end of file diff --git a/Source/Constraint/RigidBodyConstraints/imstkRbdDistanceConstraint.h b/Source/Constraint/RigidBodyConstraints/imstkRbdDistanceConstraint.h new file mode 100644 index 0000000000000000000000000000000000000000..208b69e7754ef2eb4dc7d8b3c182acf63d79fd35 --- /dev/null +++ b/Source/Constraint/RigidBodyConstraints/imstkRbdDistanceConstraint.h @@ -0,0 +1,56 @@ +/*========================================================================= + + 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 "imstkRbdConstraint.h" + +namespace imstk +{ +namespace expiremental +{ +/// +/// \class RbdDistanceConstraint +/// +/// \brief A rigid body constraint to keep objects at a specified distance +/// from each other given two local points on the bodies +/// +class RbdDistanceConstraint : public RbdConstraint +{ +public: + RbdDistanceConstraint( + std::shared_ptr<RigidBody> obj1, + std::shared_ptr<RigidBody> obj2, + const Vec3d& p1, const Vec3d& p2, + double dist, + const Side side = Side::AB); + ~RbdDistanceConstraint() override = default; + +public: + void compute(double dt) override; + +private: + Vec3d m_p1 = Vec3d(0.0, 0.0, 0.0); + Vec3d m_p2 = Vec3d(0.0, 0.0, 0.0); + double m_dist = 1.0; +}; +} +} \ No newline at end of file diff --git a/Source/Constraint/RigidBodyConstraints/imstkRbdFrictionConstraint.cpp b/Source/Constraint/RigidBodyConstraints/imstkRbdFrictionConstraint.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7bd3962046bda1bbff112081e3a86a3d156840c1 --- /dev/null +++ b/Source/Constraint/RigidBodyConstraints/imstkRbdFrictionConstraint.cpp @@ -0,0 +1,100 @@ +/*========================================================================= + + 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 "imstkRbdFrictionConstraint.h" +#include "imstkTypes.h" + +namespace imstk +{ +namespace expiremental +{ +RbdFrictionConstraint::RbdFrictionConstraint( + std::shared_ptr<RigidBody> obj1, + std::shared_ptr<RigidBody> obj2, + const Vec3d& contactNormal, + const Vec3d& contactPt, + const double contactDepth, + const double frictionCoefficient, + const Side side) : RbdConstraint(obj1, obj2, side), + m_contactN(contactNormal), m_contactPt(contactPt), + m_contactDepth(contactDepth), m_frictionCoefficient(frictionCoefficient) +{ +} + +void +RbdFrictionConstraint::compute(double imstkNotUsed(dt)) +{ + // Displacement from center of mass + //const Vec3d r1 = m_contactPt - m_obj1->getPosition(); + //const Vec3d r2 = m_contactPt - m_obj2->getPosition(); + + // Jacobian of contact + J = Eigen::Matrix<double, 3, 4>::Zero(); + if ((m_side == Side::AB || m_side == Side::A) && !m_obj1->m_isStatic) + { + const double vN = m_contactN.dot(m_obj1->getVelocity()); + const Vec3d vTan = m_obj1->getVelocity() - vN * m_contactN; + const Vec3d tan = vTan.normalized(); + + // No angular friction + J(0, 0) = -tan[0]; J(0, 1) = 0.0; + J(1, 0) = -tan[1]; J(1, 1) = 0.0; + J(2, 0) = -tan[2]; J(2, 1) = 0.0; + + const double fNMag = std::max(0.0, m_obj1->getForce().dot(-m_contactN)); + const double fu = m_frictionCoefficient * fNMag; + range[0] = -fu; + range[1] = fu; + } + if ((m_side == Side::AB || m_side == Side::B) && !m_obj2->m_isStatic) + { + const double vN = m_contactN.dot(m_obj2->getVelocity()); + const Vec3d vTan = m_obj2->getVelocity() - vN * -m_contactN; + const Vec3d tan = vTan.normalized(); + + // No angular friction + J(0, 0) = tan[0]; J(0, 1) = 0.0; + J(1, 0) = tan[1]; J(1, 1) = 0.0; + J(2, 0) = tan[2]; J(2, 1) = 0.0; + + // Get normal force + const double fNMag = std::max(0.0, m_obj2->getForce().dot(m_contactN)); + const double fu = m_frictionCoefficient * fNMag; + range[0] = -fu; + range[1] = fu; + } + + /*if both? Kinda need two ranges + { + J(0, 0) = -tan[0]; J(0, 1) = -tan[1]; J(0, 2) = -tan[2]; + J(1, 0) = 0.0; J(1, 1) = 0.0; J(1, 2) = 0.0; + J(2, 0) = tan[0]; J(2, 1) = tan[1]; J(2, 2) = tan[2]; + J(3, 0) = 0.0; J(3, 1) = 0.0; J(3, 2) = 0.0; + + const Vec3d netForce = m_obj1->getForce() + m_obj2->getForce(); + const double fNMag = std::max(0.0, netForce.dot(m_contactN)); + const double fu = m_frictionCoefficient * fNMag; + range[0] = -fu; + range[1] = fu; + }*/ +} +} +}; \ No newline at end of file diff --git a/Source/Constraint/RigidBodyConstraints/imstkRbdFrictionConstraint.h b/Source/Constraint/RigidBodyConstraints/imstkRbdFrictionConstraint.h new file mode 100644 index 0000000000000000000000000000000000000000..ea914a6fd186e5661ceeca7353022ae04a059032 --- /dev/null +++ b/Source/Constraint/RigidBodyConstraints/imstkRbdFrictionConstraint.h @@ -0,0 +1,58 @@ +/*========================================================================= + + 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 "imstkRbdConstraint.h" + +namespace imstk +{ +namespace expiremental +{ +/// +/// \class RbdFrictionConstraint +/// +/// \brief A rigid body constraint to apply friction +/// +class RbdFrictionConstraint : public RbdConstraint +{ +public: + RbdFrictionConstraint( + std::shared_ptr<RigidBody> obj1, + std::shared_ptr<RigidBody> obj2, + const Vec3d& contactPt, + const Vec3d& contactNormal, + const double contactDepth, + const double frictionCoefficient, + const Side side = Side::AB); + ~RbdFrictionConstraint() override = default; + +public: + void compute(double dt) override; + +private: + Vec3d m_contactPt; + Vec3d m_contactN; + double m_contactDepth; + double m_frictionCoefficient; +}; +} +} \ No newline at end of file diff --git a/Source/Controllers/CMakeLists.txt b/Source/Controllers/CMakeLists.txt index f4071ef623e6c0b2f9d7ce8ce4d18f731201fd93..bac492accc26a51c22445059e6e0fe2960bb27cd 100644 --- a/Source/Controllers/CMakeLists.txt +++ b/Source/Controllers/CMakeLists.txt @@ -1,6 +1,7 @@ #----------------------------------------------------------------------------- # Create target #----------------------------------------------------------------------------- + include(imstkAddLibrary) imstk_add_library( Controllers DEPENDS diff --git a/Source/Controllers/imstkCameraController.cpp b/Source/Controllers/imstkCameraController.cpp index 5f2eabe19e2ea692e17e1370bcf8be53917c493b..eaa7be685b77439e76dcb80337370a091b23db49 100644 --- a/Source/Controllers/imstkCameraController.cpp +++ b/Source/Controllers/imstkCameraController.cpp @@ -20,32 +20,26 @@ =========================================================================*/ #include "imstkCameraController.h" -#include "imstkMath.h" #include "imstkCamera.h" #include "imstkLogger.h" -#include <utility> - namespace imstk { CameraController::CameraController(std::shared_ptr<Camera> camera, std::shared_ptr<DeviceClient> deviceClient) : - Module("Camera controller"), - m_camera(camera), - m_cameraTranslationOffset(WORLD_ORIGIN), - m_cameraRotationalOffset(Quatd::Identity()), - DeviceTracker(deviceClient) + TrackingDeviceControl(deviceClient), + m_camera(camera) { } void -CameraController::runModule() +CameraController::update() { if (!m_trackingDataUptoDate) { if (!updateTrackingData()) { - LOG(WARNING) << "CameraController::runModule warning: could not update tracking info."; + LOG(WARNING) << "CameraController::runModule warning: could not update tracking info"; return; } } @@ -54,8 +48,8 @@ CameraController::runModule() Quatd r = getRotation(); // Apply Offsets over the device pose - p = p + m_cameraTranslationOffset; // Offset the device position - r *= m_cameraRotationalOffset; // Apply camera head rotation offset + p = p + m_translationOffset; // Offset the device position + r *= m_rotationOffset; // Apply camera head rotation offset // Set camera info m_camera->setPosition(p); @@ -68,9 +62,9 @@ CameraController::runModule() void CameraController::setOffsetUsingCurrentCameraPose() { - auto pos = m_camera->getPosition(); - auto viewUp = m_camera->getViewUp(); - auto focus = m_camera->getFocalPoint(); + const auto pos = m_camera->getPosition(); + const auto focus = m_camera->getFocalPoint(); + auto viewUp = m_camera->getViewUp(); m_translationOffset = pos; @@ -83,28 +77,4 @@ CameraController::setOffsetUsingCurrentCameraPose() rot.col(2) = viewNormal; m_rotationOffset = Quatd(rot); } - -void -CameraController::setCameraRotationOffset(const Quatd& r) -{ - m_cameraRotationalOffset = r; -} - -void -CameraController::setCameraTranslationOffset(const Vec3d& t) -{ - m_cameraTranslationOffset = t; -} - -const Vec3d& -CameraController::getCameraTranslationOffset() const -{ - return m_cameraTranslationOffset; -} - -const Quatd& -CameraController::getCameraRotationOffset() const -{ - return m_cameraRotationalOffset; -} -} // imstk +} \ No newline at end of file diff --git a/Source/Controllers/imstkCameraController.h b/Source/Controllers/imstkCameraController.h index 2e7272ba097eede43a09324ecd552fc4c4e72eec..908501f2e86ed5d7d21fca34c8bf38d918ffe1dc 100644 --- a/Source/Controllers/imstkCameraController.h +++ b/Source/Controllers/imstkCameraController.h @@ -21,8 +21,8 @@ #pragma once -#include "imstkModule.h" -#include "imstkDeviceTracker.h" +#include "imstkTrackingDeviceControl.h" +#include "imstkLoopThreadObject.h" namespace imstk { @@ -31,57 +31,27 @@ class Camera; /// /// \class CameraController /// -/// \brief +/// \brief \todo ?? /// -class CameraController : public Module, public DeviceTracker +class CameraController : public TrackingDeviceControl { public: - /// - /// \brief TODO - /// CameraController(std::shared_ptr<Camera> camera, std::shared_ptr<DeviceClient> deviceClient); + virtual ~CameraController() = default; - /// - /// \brief - /// - ~CameraController() = default; - +public: /// /// \brief Set the offsets based on the current camera pose /// void setOffsetUsingCurrentCameraPose(); /// - /// \brief Get/Set translation offset of the camera - /// - const Vec3d& getCameraTranslationOffset() const; - void setCameraTranslationOffset(const Vec3d& t); - - /// - /// \brief Get/Set rotation offset of the camera + /// \brief Updates the view of the provided camera /// - const Quatd& getCameraRotationOffset() const; - void setCameraRotationOffset(const Quatd& r); + void update() override; protected: - /// - /// \brief TODO - /// - virtual void initModule() override {}; - - /// - /// \brief TODO - /// - virtual void runModule() override; - - /// - /// \brief TODO - /// - void cleanUpModule() override {}; - - std::shared_ptr<Camera> m_camera; ///< Camera controlled by the external device - Vec3d m_cameraTranslationOffset; ///< Translation offset for the camera over tracking data - Quatd m_cameraRotationalOffset; ///< camera head angle offset (in deg) + std::shared_ptr<Camera> m_camera; ///< Camera controlled by the external device }; } // imstk diff --git a/Source/Controllers/imstkDeviceControl.h b/Source/Controllers/imstkDeviceControl.h new file mode 100644 index 0000000000000000000000000000000000000000..3571dc3781d5cc6233db95315d902f6ddc92deba --- /dev/null +++ b/Source/Controllers/imstkDeviceControl.h @@ -0,0 +1,65 @@ +/*========================================================================= + + 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 "imstkEventObject.h" + +#include <memory> + +namespace imstk +{ +class DeviceClient; + +/// +/// \class DeviceControl +/// +/// \brief While the DeviceClient provides quantities from the device, the control +/// defines what to do with those quantities +/// +class DeviceControl : public EventObject +{ +protected: + DeviceControl() = default; + DeviceControl(std::shared_ptr<DeviceClient> device) : m_deviceClient(device) { } + +public: + virtual ~DeviceControl() = default; + +public: + std::shared_ptr<DeviceClient> getDevice() const { return m_deviceClient; } + + virtual void setDevice(std::shared_ptr<DeviceClient> device) { m_deviceClient = device; } + + /// + /// \brief Prints the controls + /// + virtual void printControls() { } + + /// + /// \brief Updates the state of the control + /// + virtual void update() { } + +public: + std::shared_ptr<DeviceClient> m_deviceClient; +}; +} // imstk diff --git a/Source/Controllers/imstkKeyboardControl.cpp b/Source/Controllers/imstkKeyboardControl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9813fcfc1b3fea81cf8bbce45afbd31e19077d14 --- /dev/null +++ b/Source/Controllers/imstkKeyboardControl.cpp @@ -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. + +=========================================================================*/ + +#include "imstkKeyboardControl.h" +#include "imstkKeyboardDeviceClient.h" + +namespace imstk +{ +KeyboardControl::KeyboardControl(std::shared_ptr<KeyboardDeviceClient> keyDevice) : + DeviceControl(keyDevice) +{ + setDevice(keyDevice); +} + +void +KeyboardControl::setDevice(std::shared_ptr<DeviceClient> device) +{ + // Remove old observer if it exists + if (m_keyboardDeviceClient != nullptr) + { + disconnect(m_keyboardDeviceClient, this, EventType::KeyPress); + } + + // Set the new device + m_keyboardDeviceClient = std::dynamic_pointer_cast<KeyboardDeviceClient>(device); + DeviceControl::setDevice(device); + + // Subscribe to the device clients events + connect(m_keyboardDeviceClient, EventType::KeyPress, this, &KeyboardControl::keyPressEvent); +} + +void +KeyboardControl::keyPressEvent(KeyPressEvent* keyPressEvent) +{ + // If the key was just pressed + if (keyPressEvent->m_keyPressType == KEY_PRESS) + { + OnKeyPress(keyPressEvent->m_key); + } + // If the key was just released + else if (keyPressEvent->m_keyPressType == KEY_RELEASE) + { + OnKeyRelease(keyPressEvent->m_key); + } +} +} \ No newline at end of file diff --git a/Source/Controllers/imstkKeyboardControl.h b/Source/Controllers/imstkKeyboardControl.h new file mode 100644 index 0000000000000000000000000000000000000000..390c9891e13958aa7321b56d32696b916a9cdf61 --- /dev/null +++ b/Source/Controllers/imstkKeyboardControl.h @@ -0,0 +1,63 @@ +/*========================================================================= + + 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 "imstkDeviceControl.h" +#include "imstkTypes.h" + +namespace imstk +{ +class KeyboardDeviceClient; +class KeyPressEvent; + +/// +/// \class KeyboardSceneController +/// +/// \brief This is the base class for keyboard based controls +/// You can construct this and observe it or subclass and override +/// to implement controls. +/// +class KeyboardControl : public DeviceControl +{ +public: + KeyboardControl() { } + KeyboardControl(std::shared_ptr<KeyboardDeviceClient> keyDevice); + virtual ~KeyboardControl() override = default; + +public: + virtual void setDevice(std::shared_ptr<DeviceClient> device) override; + +public: + virtual void OnKeyPress(const char imstkNotUsed(key)) { } + + virtual void OnKeyRelease(const char imstkNotUsed(key)) { } + + /// + /// \brief Posts key press/release events + /// override to filter the event, or implement OnkeyDown/OnKeyUp + /// + virtual void keyPressEvent(KeyPressEvent* e); + +protected: + std::shared_ptr<KeyboardDeviceClient> m_keyboardDeviceClient; +}; +} diff --git a/Source/Controllers/imstkLaparoscopicToolController.cpp b/Source/Controllers/imstkLaparoscopicToolController.cpp index f478a84817e5179a290b690b73fbb4afdadd82c1..1aacbc3cb9bddaacedaff70dbfdc90976e6e9fe5 100644 --- a/Source/Controllers/imstkLaparoscopicToolController.cpp +++ b/Source/Controllers/imstkLaparoscopicToolController.cpp @@ -23,52 +23,47 @@ #include "imstkCollidingObject.h" #include "imstkDeviceClient.h" #include "imstkGeometry.h" -#include "imstkSceneObject.h" #include "imstkLogger.h" -#include "imstkMath.h" - -#include <utility> namespace imstk { LaparoscopicToolController::LaparoscopicToolController( - std::shared_ptr<SceneObject> shaft, - std::shared_ptr<SceneObject> upperJaw, - std::shared_ptr<SceneObject> lowerJaw, - std::shared_ptr<DeviceTracker> trackingController) : - SceneObjectControllerBase(), - m_trackingController(trackingController), + std::shared_ptr<SceneObject> shaft, + std::shared_ptr<SceneObject> upperJaw, + std::shared_ptr<SceneObject> lowerJaw, + std::shared_ptr<DeviceClient> trackingDevice) : + TrackingDeviceControl(trackingDevice), m_shaft(shaft), m_upperJaw(upperJaw), m_lowerJaw(lowerJaw), m_jawRotationAxis(Vec3d(0, 1., 0)) { - m_trackingController->getDeviceClient()->setButtonsEnabled(true); + trackingDevice->setButtonsEnabled(true); } void LaparoscopicToolController::updateControlledObjects() { - if (!m_trackingController->isTrackerUpToDate()) + if (!isTrackerUpToDate()) { - if (!m_trackingController->updateTrackingData()) + if (!updateTrackingData()) { LOG(WARNING) << "LaparoscopicToolController::updateControlledObjects warning: could not update tracking info."; return; } } - Vec3d p = m_trackingController->getPosition(); - Quatd r = m_trackingController->getRotation(); + Vec3d p = getPosition(); + Quatd r = getRotation(); // Update jaw angles - if (m_trackingController->getDeviceClient()->getButton(0)) + if (m_deviceClient->getButton(0)) { m_jawAngle += m_change; m_jawAngle = (m_jawAngle > m_maxJawAngle) ? m_maxJawAngle : m_jawAngle; } - if (m_trackingController->getDeviceClient()->getButton(1)) + if (m_deviceClient->getButton(1)) { m_jawAngle -= m_change; m_jawAngle = (m_jawAngle < 0.0) ? 0.0 : m_jawAngle; @@ -111,6 +106,6 @@ LaparoscopicToolController::applyForces() force += collidingObject->getForce(); } - m_trackingController->getDeviceClient()->setForce(force); + m_deviceClient->setForce(force); } } // imstk diff --git a/Source/Controllers/imstkLaparoscopicToolController.h b/Source/Controllers/imstkLaparoscopicToolController.h index ad05a19728e25e2266a957b88e1700dead8af344..2c1e1c9c41d504478ec2cafe31863fbe9de52a16 100644 --- a/Source/Controllers/imstkLaparoscopicToolController.h +++ b/Source/Controllers/imstkLaparoscopicToolController.h @@ -21,8 +21,7 @@ #pragma once -#include "imstkSceneObjectControllerBase.h" -#include "imstkDeviceTracker.h" +#include "imstkTrackingDeviceControl.h" namespace imstk { @@ -36,25 +35,23 @@ class SceneObject; /// The jaws open-close based on the buttons at present. /// This has to be replaced by potentiometer tracking in future. /// -class LaparoscopicToolController : public SceneObjectControllerBase +class LaparoscopicToolController : public TrackingDeviceControl { public: /// /// \brief Constructor /// LaparoscopicToolController( - std::shared_ptr<SceneObject> shaft, - std::shared_ptr<SceneObject> upperJaw, - std::shared_ptr<SceneObject> lowerJaw, - std::shared_ptr<DeviceTracker> trackingController); + std::shared_ptr<SceneObject> shaft, + std::shared_ptr<SceneObject> upperJaw, + std::shared_ptr<SceneObject> lowerJaw, + std::shared_ptr<DeviceClient> trackingDevice); LaparoscopicToolController() = delete; //not allowed for now - /// - /// \brief Destructor - /// - ~LaparoscopicToolController() = default; + ~LaparoscopicToolController() override = default; +public: /// /// \brief Update controlled laparoscopic tool using latest tracking information /// @@ -65,11 +62,6 @@ public: /// void applyForces() override; - /// - /// \brief Set the tracker to out-of-date - /// - inline void setTrackerToOutOfDate() override { m_trackingController->setTrackerToOutOfDate(); } - /// /// \brief Set the maximum jaw angle /// @@ -95,16 +87,7 @@ public: /// inline double getMaxJawAngle() const { return m_maxJawAngle; } - /// - /// \brief Get/Set tracking controller - /// - inline std::shared_ptr<DeviceTracker> getTrackingController() const { return m_trackingController; } - inline void setTrackingController(std::shared_ptr<DeviceTracker> controller) { m_trackingController = controller; } - protected: - - std::shared_ptr<DeviceTracker> m_trackingController; ///< Device tracker - std::shared_ptr<SceneObject> m_shaft; ///< Tool shaft std::shared_ptr<SceneObject> m_upperJaw; ///< Tool upper jaw std::shared_ptr<SceneObject> m_lowerJaw; ///< Tool lower jaw diff --git a/Source/Controllers/imstkMouseControl.cpp b/Source/Controllers/imstkMouseControl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..497c40ecaca1657bb7bd7dc4fa12320b154e0ab2 --- /dev/null +++ b/Source/Controllers/imstkMouseControl.cpp @@ -0,0 +1,71 @@ +/*========================================================================= + + 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 "imstkMouseControl.h" +#include "imstkMouseDeviceClient.h" + +namespace imstk +{ +MouseControl::MouseControl(std::shared_ptr<MouseDeviceClient> mouseDevice) : + DeviceControl(mouseDevice) +{ + setDevice(mouseDevice); +} + +void +MouseControl::setDevice(std::shared_ptr<DeviceClient> device) +{ + // Remove old observer if it exists + if (m_mouseDeviceClient != nullptr) + { + disconnect(m_mouseDeviceClient, this, EventType::MouseEvent); + } + + // Set the new device + m_mouseDeviceClient = std::dynamic_pointer_cast<MouseDeviceClient>(device); + DeviceControl::setDevice(device); + + // Subscribe to the device clients events + connect(m_mouseDeviceClient, EventType::MouseEvent, this, &MouseControl::mouseEvent); +} + +void +MouseControl::mouseEvent(MouseEvent* e) +{ + switch (e->m_mouseActionType) + { + case MOUSE_PRESS: + OnButtonPress(e->m_buttonId); + break; + case MOUSE_RELEASE: + OnButtonRelease(e->m_buttonId); + break; + case MOUSE_SCROLL: + OnScroll(e->m_scrollDx); + break; + case MOUSE_MOVE: + OnMouseMove(m_mouseDeviceClient->getPos()); + default: + break; + } + ; +} +} \ No newline at end of file diff --git a/Source/Controllers/imstkMouseControl.h b/Source/Controllers/imstkMouseControl.h new file mode 100644 index 0000000000000000000000000000000000000000..13f4a33a20825db1d31dd374d22df45e76738dbf --- /dev/null +++ b/Source/Controllers/imstkMouseControl.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. + +=========================================================================*/ + +#pragma once + +#include "imstkDeviceControl.h" +#include "imstkMath.h" +#include "imstkTypes.h" + +namespace imstk +{ +class MouseDeviceClient; +class MouseEvent; + +/// +/// \class MouseControl +/// +/// \brief This is the base class for mouse based controls +/// It can be constructed and observed or subclassed and overridden +/// to implement controls. +/// +class MouseControl : public DeviceControl +{ +public: + MouseControl() = default; + MouseControl(std::shared_ptr<MouseDeviceClient> mouseDevice); + virtual ~MouseControl() override = default; + +public: + virtual void setDevice(std::shared_ptr<DeviceClient> device) override; + +public: + virtual void OnButtonPress(const int imstkNotUsed(key)) { } + + virtual void OnButtonRelease(const int imstkNotUsed(key)) { } + + virtual void OnScroll(const double imstkNotUsed(dx)) { } + + virtual void OnMouseMove(const Vec2d& imstkNotUsed(pos)) { } + + /// + /// \brief Posts key press/release events + /// override to filter the event, or implement OnkeyDown/OnKeyUp + /// + virtual void mouseEvent(MouseEvent* e); + +protected: + std::shared_ptr<MouseDeviceClient> m_mouseDeviceClient; +}; +} diff --git a/Source/Controllers/imstkRigidObjectController.cpp b/Source/Controllers/imstkRigidObjectController.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2eaf23f48c797b83e22938f03a65de0f44818e2d --- /dev/null +++ b/Source/Controllers/imstkRigidObjectController.cpp @@ -0,0 +1,105 @@ +/*========================================================================= + + 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 "imstkRigidObjectController.h" +#include "imstkCollidingObject.h" +#include "imstkDeviceClient.h" +#include "imstkGeometry.h" +#include "imstkLogger.h" +#include "imstkRbdConstraint.h" +#include "imstkRigidObject2.h" + +namespace imstk +{ +namespace expiremental +{ +RigidObjectController::RigidObjectController(std::shared_ptr<RigidObject2> rigidObject, + std::shared_ptr<DeviceClient> trackingDevice) : + SceneObjectController(rigidObject, trackingDevice), + m_rigidObject(rigidObject) +{ + /*m_currentPos = rigidObject->getRigidBody()->getPosition(); + m_currentRot = rigidObject->getRigidBody()->getOrientation();*/ +} + +void +RigidObjectController::updateControlledObjects() +{ + if (!isTrackerUpToDate()) + { + if (!updateTrackingData()) + { + LOG(WARNING) << "SceneObjectController::updateControlledObjects warning: could not update tracking info."; + return; + } + } + + this->postEvent(Event(EventType::Modified)); + + // During initialization tracking may not be enabled for a time, in which case, freeze the thing + // or else extraneous forces may be applied towards uninitialized position (0, 0, 0) or gravity + // pull it down + if (!m_deviceClient->getTrackingEnabled()) + { + (*m_rigidObject->getRigidBody()->m_pos) = m_rigidObject->getRigidBody()->m_initPos; + (*m_rigidObject->getRigidBody()->m_orientation) = m_rigidObject->getRigidBody()->m_initOrientation; + return; + } + + // Apply virtual coupling + const Vec3d currPos = m_rigidObject->getRigidBody()->getPosition(); + const Vec3d desiredPos = getPosition(); + { + const Vec3d diff = desiredPos - currPos; + //const double length = diff.norm(); + //const Vec3d dir = diff.normalized(); + + const Vec3d fS = m_linearKs.cwiseProduct(diff); + const Vec3d fD = m_rigidObject->getRigidBody()->getVelocity() * -m_linearKd; + + // Apply spring force and general damper + (*m_rigidObject->getRigidBody()->m_force) += (fS + fD); + } + + const Quatd currOrientation = m_rigidObject->getRigidBody()->getOrientation(); + const Quatd desiredOrientation = getRotation(); + { + // q gives the delta rotation that gets us from curr->desired + const Quatd dq = desiredOrientation * currOrientation.inverse(); + // Get the rotation axes + Rotd angleAxes = Rotd(dq); + angleAxes.axis().normalize(); + + // Because the scale of the *magnitude* of the rotation done is controllable + // it doesn't matter if its exact, ksTheta can just be adjusted + (*m_rigidObject->getRigidBody()->m_torque) += (angleAxes.axis() * angleAxes.angle()).cwiseProduct(m_rotKs); + } +} + +void +RigidObjectController::applyForces() +{ + // Apply force back to device + m_deviceClient->setForce(m_rigidObject->getRigidBody()->getForce()); + //m_deviceClient->setTorque(); +} +} +} diff --git a/Source/Controllers/imstkRigidObjectController.h b/Source/Controllers/imstkRigidObjectController.h new file mode 100644 index 0000000000000000000000000000000000000000..a5bba421ed7197cb26d9e78b15852583f6e074f4 --- /dev/null +++ b/Source/Controllers/imstkRigidObjectController.h @@ -0,0 +1,91 @@ +/*========================================================================= + + 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 "imstkSceneObjectController.h" + +namespace imstk +{ +namespace expiremental +{ +class RigidObject2; + +/// +/// \class RigidObjectController +/// +/// \brief This class uses the provide device to control the provided rigid object via +/// virtual coupling. That is, it applies forces+torques to the rigid body that will +/// help move it to desired position/orientation +/// +class RigidObjectController : public SceneObjectController +{ +public: + /// + /// \brief Constructor + /// + RigidObjectController(std::shared_ptr<RigidObject2> rigidObject, std::shared_ptr<DeviceClient> trackingDevice); + RigidObjectController() = delete; + + /// + /// \brief Destructor + /// + virtual ~RigidObjectController() override = default; + +public: + /// + /// \brief Set/Get the linear damping coefficient + /// + double getLinearKd() const { return m_linearKd; } + void setLinearKd(double kd) { m_linearKd = kd; } + + /// + /// \brief Set/Get the linear spring coefficient + /// + const Vec3d& getLinearKs() const { return m_linearKs; } + void setLinearKs(const Vec3d& ks) { m_linearKs = ks; } + + /// + /// \brief Set/Get the rotationl spring coefficient + /// + const Vec3d& getRotKs() const { return m_rotKs; } + void setRotationalKs(const Vec3d& ks) { m_rotKs = ks; } + +public: + /// + /// \brief Update controlled scene object using latest tracking information + /// + void updateControlledObjects() override; + + /// + /// \brief Apply forces to the haptic device + /// + void applyForces() override; + +protected: + std::shared_ptr<RigidObject2> m_rigidObject; + + double m_linearKd = 800.0; ///> Damping coefficient, linear + Vec3d m_linearKs = Vec3d(2000000.0, 2000000.0, 2000000.0); ///> Spring coefficient, linear + Vec3d m_rotKs = Vec3d(1000.0, 1000.0, 1000.0); //.> Spring coefficient, rotational +}; +} +} diff --git a/Source/Controllers/imstkSceneObjectController.cpp b/Source/Controllers/imstkSceneObjectController.cpp index 1b6a94a8e151a4a2d0c8d20ad62bbec0f0306c62..0913ff36e4e2538321b39e9ffa9f5f9ba99ecb87 100644 --- a/Source/Controllers/imstkSceneObjectController.cpp +++ b/Source/Controllers/imstkSceneObjectController.cpp @@ -20,40 +20,48 @@ =========================================================================*/ #include "imstkSceneObjectController.h" -#include "imstkDeviceTracker.h" -#include "imstkSceneObject.h" -#include "imstkDeviceClient.h" #include "imstkCollidingObject.h" +#include "imstkDeviceClient.h" #include "imstkGeometry.h" #include "imstkLogger.h" namespace imstk { -SceneObjectController::SceneObjectController(std::shared_ptr<SceneObject> sceneObject, std::shared_ptr<DeviceTracker> trackingController) : - m_trackingController(trackingController), m_sceneObject(sceneObject) +SceneObjectController::SceneObjectController(std::shared_ptr<SceneObject> sceneObject, + std::shared_ptr<DeviceClient> trackingDevice) : + TrackingDeviceControl(trackingDevice), + m_sceneObject(sceneObject) { } void SceneObjectController::updateControlledObjects() { - if (!m_trackingController->isTrackerUpToDate()) + if (!isTrackerUpToDate()) { - if (!m_trackingController->updateTrackingData()) + if (!updateTrackingData()) { LOG(WARNING) << "SceneObjectController::updateControlledObjects warning: could not update tracking info."; return; } } - if (m_updateCallback) + if (m_sceneObject == nullptr) + { + return; + } + + if (!m_deviceClient->getTrackingEnabled()) { - m_updateCallback(this); + return; } - // Update colliding geometry - m_sceneObject->getMasterGeometry()->setTranslation(m_trackingController->getPosition()); - m_sceneObject->getMasterGeometry()->setRotation(m_trackingController->getRotation()); + this->postEvent(Event(EventType::Modified)); + + // Update geometry + // \todo revisit this; what if we need to move a group of objects + m_sceneObject->getMasterGeometry()->setTranslation(getPosition()); + m_sceneObject->getMasterGeometry()->setRotation(getRotation()); } void @@ -61,13 +69,7 @@ SceneObjectController::applyForces() { if (auto collidingObject = dynamic_cast<CollidingObject*>(m_sceneObject.get())) { - m_trackingController->getDeviceClient()->setForce(collidingObject->getForce()); + m_deviceClient->setForce(collidingObject->getForce()); } } - -void -SceneObjectController::setTrackerToOutOfDate() -{ - m_trackingController->setTrackerToOutOfDate(); -} -} // imstk +} \ No newline at end of file diff --git a/Source/Controllers/imstkSceneObjectController.h b/Source/Controllers/imstkSceneObjectController.h index 9a35ead4c5a8c8b873c513abc7c3ebd3e03b16d2..914430fb7dc5d6a1e599d48e5fdb5f88d597a593 100644 --- a/Source/Controllers/imstkSceneObjectController.h +++ b/Source/Controllers/imstkSceneObjectController.h @@ -21,74 +21,44 @@ #pragma once -#include "imstkSceneObjectControllerBase.h" +#include "imstkTrackingDeviceControl.h" -#include <memory> #include <functional> namespace imstk { class SceneObject; -class DeviceTracker; /// /// \class SceneObjectController /// -/// \brief This class implements once tracking controller controlling one scnene object +/// \brief This class implements once tracking controller controlling one scene object /// -class SceneObjectController : public SceneObjectControllerBase +class SceneObjectController : public TrackingDeviceControl { -using ControllerCallbackFunction = std::function<void (SceneObjectController* hdapiClient)>; - public: - /// - /// \brief Constructor - /// - SceneObjectController(std::shared_ptr<SceneObject> sceneObject, std::shared_ptr<DeviceTracker> trackingController); - + SceneObjectController(std::shared_ptr<SceneObject> sceneObject, std::shared_ptr<DeviceClient> trackingDevice); SceneObjectController() = delete; + virtual ~SceneObjectController() override = default; - /// - /// \brief Destructor - /// - ~SceneObjectController() = default; - +public: /// /// \brief Update controlled scene object using latest tracking information /// void updateControlledObjects() override; /// - /// \brief Apply forces to the haptic device + /// \brief Apply forces to the haptic-capable device /// void applyForces() override; - /// - /// \brief Sets the tracker to out-of-date - /// - void setTrackerToOutOfDate() override; - /// /// \brief Get/Set controlled scene object /// inline std::shared_ptr<SceneObject> getControlledSceneObject() const { return m_sceneObject; } inline void setControlledSceneObject(std::shared_ptr<SceneObject> so) { m_sceneObject = so; } - /// - /// \brief Get/Set tracking controller - /// - inline std::shared_ptr<DeviceTracker> getTrackingController() const { return m_trackingController; } - inline void setTrackingController(std::shared_ptr<DeviceTracker> controller) { m_trackingController = controller; } - - /// - /// \brief Setting custom behavior functions - /// - inline void setUpdateCallback(ControllerCallbackFunction foo) { m_updateCallback = foo; } - protected: - std::shared_ptr<DeviceTracker> m_trackingController; ///< Device tracker - std::shared_ptr<SceneObject> m_sceneObject; ///< SceneObject controlled by the Tracker - //Callback functions - ControllerCallbackFunction m_updateCallback; ///> function callback preceding module update + std::shared_ptr<SceneObject> m_sceneObject; ///< SceneObject controlled by the Tracker }; } // imstk diff --git a/Source/Controllers/imstkDeviceTracker.cpp b/Source/Controllers/imstkTrackingDeviceControl.cpp similarity index 76% rename from Source/Controllers/imstkDeviceTracker.cpp rename to Source/Controllers/imstkTrackingDeviceControl.cpp index 7ed271c3423f2a69460d42d0caea063041907a54..29407d62bbfd5205fa860fa7cb37eda5de440f4f 100644 --- a/Source/Controllers/imstkDeviceTracker.cpp +++ b/Source/Controllers/imstkTrackingDeviceControl.cpp @@ -19,24 +19,28 @@ =========================================================================*/ -#include "imstkMath.h" -#include "imstkDeviceTracker.h" +#include "imstkTrackingDeviceControl.h" #include "imstkDeviceClient.h" #include "imstkLogger.h" - -#include <utility> +#include "imstkMath.h" namespace imstk { -DeviceTracker::DeviceTracker(std::shared_ptr<DeviceClient> deviceClient) : - m_deviceClient(deviceClient), +TrackingDeviceControl::TrackingDeviceControl() : + m_translationOffset(WORLD_ORIGIN), + m_rotationOffset(Quatd::Identity()) +{ +} + +TrackingDeviceControl::TrackingDeviceControl(std::shared_ptr<DeviceClient> device) : + DeviceControl(device), m_translationOffset(WORLD_ORIGIN), m_rotationOffset(Quatd::Identity()) { } bool -DeviceTracker::updateTrackingData() +TrackingDeviceControl::updateTrackingData() { if (m_deviceClient == nullptr) { @@ -44,6 +48,8 @@ DeviceTracker::updateTrackingData() return false; } + m_deviceClient->update(); + // Retrieve device info m_currentPos = m_deviceClient->getPosition(); m_currentRot = m_deviceClient->getOrientation(); @@ -83,62 +89,50 @@ DeviceTracker::updateTrackingData() return true; } -std::shared_ptr<DeviceClient> -DeviceTracker::getDeviceClient() const -{ - return m_deviceClient; -} - -void -DeviceTracker::setDeviceClient(std::shared_ptr<DeviceClient> deviceClient) -{ - m_deviceClient = deviceClient; -} - double -DeviceTracker::getTranslationScaling() const +TrackingDeviceControl::getTranslationScaling() const { return m_scaling; } void -DeviceTracker::setTranslationScaling(double scaling) +TrackingDeviceControl::setTranslationScaling(const double scaling) { m_scaling = scaling; } const Vec3d& -DeviceTracker::getTranslationOffset() const +TrackingDeviceControl::getTranslationOffset() const { return m_translationOffset; } void -DeviceTracker::setTranslationOffset(const Vec3d& t) +TrackingDeviceControl::setTranslationOffset(const Vec3d& t) { m_translationOffset = t; } const Quatd& -DeviceTracker::getRotationOffset() +TrackingDeviceControl::getRotationOffset() { return m_rotationOffset; } void -DeviceTracker::setRotationOffset(const Quatd& r) +TrackingDeviceControl::setRotationOffset(const Quatd& r) { m_rotationOffset = r; } unsigned char -DeviceTracker::getInversionFlags() +TrackingDeviceControl::getInversionFlags() { return m_invertFlags; } void -DeviceTracker::setInversionFlags(unsigned char f) +TrackingDeviceControl::setInversionFlags(const unsigned char f) { m_invertFlags = f; } diff --git a/Source/Controllers/imstkDeviceTracker.h b/Source/Controllers/imstkTrackingDeviceControl.h similarity index 69% rename from Source/Controllers/imstkDeviceTracker.h rename to Source/Controllers/imstkTrackingDeviceControl.h index 6b6914f382766a01315448f7872137cf89c202f3..c887b5edd4cab5ba59084aa52e28b5e6a2208536 100644 --- a/Source/Controllers/imstkDeviceTracker.h +++ b/Source/Controllers/imstkTrackingDeviceControl.h @@ -21,25 +21,21 @@ #pragma once +#include "imstkDeviceControl.h" #include "imstkMath.h" namespace imstk { -class DeviceClient; - /// -/// \class DeviceTracker +/// \class TrackingDeviceControl /// -/// \brief This class reports external device's position and orientation with a given offset +/// \brief Base class for all DeviceControls that track +/// something in space (position and orientation) +/// ?? rename with 'spacial' in it? /// -class DeviceTracker +class TrackingDeviceControl : public DeviceControl { public: - - /// - /// \enum - /// \brief TODO - /// enum InvertFlag { transX = 0x01, @@ -50,32 +46,59 @@ public: rotZ = 0x20 }; +public: + TrackingDeviceControl(); + TrackingDeviceControl(std::shared_ptr<DeviceClient> device); + virtual ~TrackingDeviceControl() override = default; + +public: /// - /// \brief Constructor + /// \brief Update controlled scene objects using latest tracking information + /// \todo get rid of updateControlledObjects? replace with update (from DeviceControl) /// - explicit DeviceTracker(std::shared_ptr<DeviceClient> deviceClient); + virtual void updateControlledObjects() {} /// - /// \brief Destructor + /// \brief Apply forces to the haptic device /// - ~DeviceTracker() = default; + virtual void applyForces() {} /// - /// \brief Compute the world position and orientation + /// \brief Sets the tracking data to be out of date or up to date /// - bool updateTrackingData(); + void setTrackerToOutOfDate() { m_trackingDataUptoDate = false; } + void setTrackerToUpToDate() { m_trackingDataUptoDate = true; } /// - /// \brief Get/Set the device client + /// \brief Returns true if the tracking data is already updated in current frame. Else, false. + /// + bool isTrackerUpToDate() const { return m_trackingDataUptoDate; } + + /// + /// \brief Get the latest position /// - std::shared_ptr<DeviceClient> getDeviceClient() const; - void setDeviceClient(std::shared_ptr<DeviceClient> deviceClient); + const Vec3d& getPosition() const { return m_currentPos; }; + + /// + /// \brief Set the position of the tracker + /// + void setPosition(const Vec3d& pos) { this->m_currentPos = pos; } + + /// + /// \brief Get the latest rotation + /// + const Quatd& getRotation() const { return m_currentRot; }; + + /// + /// \brief Set the orientation of the tracker + /// + void setRotation(const Quatd& orientation) { this->m_currentRot = orientation; } /// /// \brief Get/Set the current scaling factor /// double getTranslationScaling() const; - void setTranslationScaling(double scaling); + void setTranslationScaling(const double scaling); /// /// \brief Get/Set the translation offset @@ -93,32 +116,14 @@ public: /// \brief Get/Set the inversion flags /// unsigned char getInversionFlags(); - void setInversionFlags(unsigned char f); - - /// - /// \brief Sets the tracking data to be out of date or up to date - /// - void setTrackerToOutOfDate() { m_trackingDataUptoDate = false; } - void setTrackerToUpToDate() { m_trackingDataUptoDate = true; } + void setInversionFlags(const unsigned char f); /// - /// \brief Returns true if the tracking data is already updated in current frame. Else, false. - /// - bool isTrackerUpToDate() const { return m_trackingDataUptoDate; } - - /// - /// \brief Get the latest position - /// - const Vec3d& getPosition() { return m_currentPos; }; - - /// - /// \brief Get the latest rotation + /// \brief Compute the world position and orientation /// - const Quatd& getRotation() { return m_currentRot; }; + bool updateTrackingData(); protected: - - std::shared_ptr<DeviceClient> m_deviceClient; ///< Reports device tracking information double m_scaling = 1.0; ///< Scaling factor for physical to virtual translations Vec3d m_translationOffset; ///< Translation concatenated to the device translation Quatd m_rotationOffset; ///< Rotation concatenated to the device rotation @@ -126,6 +131,6 @@ protected: Vec3d m_currentPos; Quatd m_currentRot; - bool m_trackingDataUptoDate = false; ///< Keeps track of the device update in a given frame + bool m_trackingDataUptoDate = false; }; } // imstk diff --git a/Source/DataStructures/Testing/imstkLooseOctreeTest.cpp b/Source/DataStructures/Testing/imstkLooseOctreeTest.cpp index f012ed0a4fa139ec3d63e56a8ba7c6ca670a16d2..b87fee611f7e24502cf68205b62ed67569beba8d 100644 --- a/Source/DataStructures/Testing/imstkLooseOctreeTest.cpp +++ b/Source/DataStructures/Testing/imstkLooseOctreeTest.cpp @@ -20,15 +20,9 @@ =========================================================================*/ #include "gtest/gtest.h" -#include "gmock/gmock.h" -#include "imstkMath.h" -#include "imstkPointSet.h" #include "imstkSurfaceMesh.h" #include "imstkLooseOctree.h" -#include "imstkParallelUtils.h" - -#include <queue> using namespace imstk; diff --git a/Source/DataStructures/Testing/imstkNeighborSearchTest.cpp b/Source/DataStructures/Testing/imstkNeighborSearchTest.cpp index f83dcd2c441b32ecb0142d114767b9347bf23772..81980ca5d8755bb720f2600258847e7d602391e3 100644 --- a/Source/DataStructures/Testing/imstkNeighborSearchTest.cpp +++ b/Source/DataStructures/Testing/imstkNeighborSearchTest.cpp @@ -20,9 +20,7 @@ =========================================================================*/ #include "gtest/gtest.h" -#include "gmock/gmock.h" -#include "imstkMath.h" #include "imstkSpatialHashTableSeparateChaining.h" #include "imstkGridBasedNeighborSearch.h" diff --git a/Source/DataStructures/imstkGraph.cpp b/Source/DataStructures/imstkGraph.cpp index 09705ed2981515b60406c28605df8b81a69bd336..f056435e7a46f5724ee72bb57db5099ba7e76ba4 100644 --- a/Source/DataStructures/imstkGraph.cpp +++ b/Source/DataStructures/imstkGraph.cpp @@ -19,17 +19,11 @@ =========================================================================*/ -#include <algorithm> -#include <numeric> -#include <map> -#include <climits> -#undef min -#undef max - #include "imstkGraph.h" +#include "imstkLogger.h" #include "imstkParallelUtils.h" -#include <g3log/g3log.hpp> +#include <numeric> namespace imstk { diff --git a/Source/DataStructures/imstkGraph.h b/Source/DataStructures/imstkGraph.h index 26ab939b2de0fb1ab8ba3ef7fa0d38f5d0a4a62a..75752ee7355f368dd36d8b9464ad5df0eea5af2f 100644 --- a/Source/DataStructures/imstkGraph.h +++ b/Source/DataStructures/imstkGraph.h @@ -22,10 +22,7 @@ #pragma once #include <unordered_set> -#include <iostream> -#include <algorithm> - -#include "imstkMath.h" +#include <vector> namespace imstk { diff --git a/Source/DataStructures/imstkGridBasedNeighborSearch.cpp b/Source/DataStructures/imstkGridBasedNeighborSearch.cpp index 56ebe4b307a6152c75bd519c42db2b69fbdf67de..20a1f90b8c957917d33bb13e43b5b3398a83fabf 100644 --- a/Source/DataStructures/imstkGridBasedNeighborSearch.cpp +++ b/Source/DataStructures/imstkGridBasedNeighborSearch.cpp @@ -21,7 +21,6 @@ #include "imstkGridBasedNeighborSearch.h" #include "imstkParallelUtils.h" -#include "imstkLogger.h" namespace imstk { diff --git a/Source/DataStructures/imstkLooseOctree.cpp b/Source/DataStructures/imstkLooseOctree.cpp index 0ef44a90ba33b6dedd8e77d4cbb2f009d2539022..1c24e579256a308128588fe6ab5732ceb49d514d 100644 --- a/Source/DataStructures/imstkLooseOctree.cpp +++ b/Source/DataStructures/imstkLooseOctree.cpp @@ -20,12 +20,9 @@ =========================================================================*/ #include "imstkLooseOctree.h" - -#include "imstkGeometry.h" -#include "imstkPointSet.h" -#include "imstkSurfaceMesh.h" #include "imstkDebugRenderGeometry.h" -//#include "imstkRenderMaterial.h" +#include "imstkLogger.h" +#include "imstkSurfaceMesh.h" namespace imstk { diff --git a/Source/DataStructures/imstkLooseOctree.h b/Source/DataStructures/imstkLooseOctree.h index d09a5cd64b896355ba7ffcfc52ccf84567d3c663..638ac6c65004ac29649d583e5b390750b41fac70 100644 --- a/Source/DataStructures/imstkLooseOctree.h +++ b/Source/DataStructures/imstkLooseOctree.h @@ -23,17 +23,13 @@ #include "imstkMath.h" #include "imstkParallelUtils.h" -#include "imstkLogger.h" #include <array> -#include <cstdint> -#include <climits> -#include <memory> -#include <unordered_map> #include <unordered_set> -#include <vector> +#ifdef WIN32 #pragma warning(disable : 4201) +#endif namespace imstk { class OctreeNode; @@ -148,6 +144,26 @@ public: /// uint32_t getPrimitiveCount(const OctreePrimitiveType type) const { return m_PrimitiveCounts[type]; } + /// + /// \brief Get the bounds of the node + /// + const Vec6d getBounds() + { + Vec6d bounds; + bounds << m_LowerBound[0], m_UpperBound[0], m_LowerBound[1], m_UpperBound[1], m_LowerBound[2], m_UpperBound[2]; + return bounds; + } + + /// + /// \brief Get the loose bounds of the node + /// + const Vec6d getLooseBounds() + { + Vec6d bounds; + bounds << m_LowerExtendedBound[0], m_UpperExtendedBound[0], m_LowerExtendedBound[1], m_UpperExtendedBound[1], m_LowerExtendedBound[2], m_UpperExtendedBound[2]; + return bounds; + } + /// /// \brief Recursively clear primitive data (linked lists and counters) /// Note that the primitives are still exist in the octree primitive list, they are just removed from the node @@ -535,6 +551,7 @@ protected: Real m_MinWidth; ///> Minimum width allowed for the tree nodes uint32_t m_MaxDepth; ///> Max depth of the tree, which is computed based on m_MinWidth + bool m_useMaxDepth; ///> If on max depth specified by user will be used, otherwise maxdepth is based of minwidth OctreeNode* const m_pRootNode; ///> Root node, should not be reassigned throughout the existence of the tree OctreeNodeBlock* m_pNodeBlockPoolHead = nullptr; ///> The pool of tree nodes, storing pre-allocated nodes as a linked list @@ -570,4 +587,6 @@ protected: bool m_bDrawNonEmptyParent = true; }; } // end namespace imstk +#ifdef WIN32 #pragma warning(default : 4201) +#endif diff --git a/Source/DataStructures/imstkSpatialHashTableSeparateChaining.h b/Source/DataStructures/imstkSpatialHashTableSeparateChaining.h index 84b4bafd4dfb7b33d5de20591b187d703e2782ed..501928348e6085f902e995925eb491d473caa73a 100644 --- a/Source/DataStructures/imstkSpatialHashTableSeparateChaining.h +++ b/Source/DataStructures/imstkSpatialHashTableSeparateChaining.h @@ -21,10 +21,10 @@ #pragma once -#include <unordered_set> - -#include "imstkMath.h" #include "imstkSpatialHashTable.h" +#include "imstkMath.h" + +#include <unordered_set> namespace imstk { diff --git a/Source/DataStructures/imstkUniformSpatialGrid.h b/Source/DataStructures/imstkUniformSpatialGrid.h index 449ac7b76212a87e75026890b06bf19c1600476c..3ed8dbfa31861d56bf730e6f2178b7734934b25a 100644 --- a/Source/DataStructures/imstkUniformSpatialGrid.h +++ b/Source/DataStructures/imstkUniformSpatialGrid.h @@ -21,11 +21,11 @@ #pragma once -#include <array> - #include "imstkMath.h" #include "imstkLogger.h" +#include <array> + namespace imstk { /// diff --git a/Source/Devices/CMakeLists.txt b/Source/Devices/CMakeLists.txt index 83e5e995fa7283bcf8e360a999df99158e1adf68..257f55e9a5ab7ed360a28a8097dc020920716f31 100644 --- a/Source/Devices/CMakeLists.txt +++ b/Source/Devices/CMakeLists.txt @@ -5,6 +5,12 @@ list(APPEND Dependencies Common VRPN) + +include(imstkAddLibrary) +set(HAPTIC_DEVICE_LIBS) +if(${PROJECT_NAME}_USE_OpenHaptics) + set(HAPTIC_DEVICE_LIBS OpenHapticsSDK) +endif() list(APPEND ExclusionFiles "") if(${PROJECT_NAME}_USE_OpenHaptics) @@ -12,17 +18,18 @@ if(${PROJECT_NAME}_USE_OpenHaptics) ${HAPTIC_DEVICE_LIBS}) else() list(APPEND ExclusionFiles - imstkHDAPIDeviceClient.h - imstkHDAPIDeviceClient.cpp - imstkHDAPIDeviceServer.h - imstkHDAPIDeviceServer.cpp) + imstkHapticDeviceClient.h + imstkHapticDeviceClient.cpp + imstkHapticDeviceManager.h + imstkHapticDeviceManager.cpp) endif() -include(imstkAddLibrary) set(HAPTIC_DEVICE_LIBS) if(${PROJECT_NAME}_USE_OpenHaptics) set(HAPTIC_DEVICE_LIBS OpenHapticsSDK) endif() + +include(imstkAddLibrary) imstk_add_library(Devices EXCLUDE_FILES ${ExclusionFiles} diff --git a/Source/Devices/imstkDeviceClient.cpp b/Source/Devices/imstkDeviceClient.cpp index 6f7f5db5c0dc0202420355f9ce1d4000fb934302..d1facf8c6e822472e937b8f2ed0584f11e348083 100644 --- a/Source/Devices/imstkDeviceClient.cpp +++ b/Source/Devices/imstkDeviceClient.cpp @@ -20,7 +20,6 @@ =========================================================================*/ #include "imstkDeviceClient.h" - #include "imstkLogger.h" namespace imstk @@ -125,24 +124,6 @@ DeviceClient::getOrientation() const return m_orientation; } -const std::map<size_t, bool>& -DeviceClient::getButtons() const -{ - return m_buttons; -} - -bool -DeviceClient::getButton(size_t buttonId) const -{ - if (m_buttons.find(buttonId) == m_buttons.end()) - { - LOG(WARNING) << "DeviceClient::getButton warning: button " - << buttonId << " was not found in the buttons list."; - return false; - } - return m_buttons.at(buttonId); -} - const Vec3d& DeviceClient::getForce() const { diff --git a/Source/Devices/imstkDeviceClient.h b/Source/Devices/imstkDeviceClient.h index 2f9bc39e7b554a322f391ced0f0e7a88c62a8991..53b2989375de05bfa284e3f5e469116447edaa20 100644 --- a/Source/Devices/imstkDeviceClient.h +++ b/Source/Devices/imstkDeviceClient.h @@ -22,22 +22,29 @@ #pragma once #include "imstkMath.h" +#include "imstkEventObject.h" + +#include <unordered_map> namespace imstk { /// /// \class DeviceClient -/// \brief Base class for any device client /// -class DeviceClient +/// \brief The device client's represents the device and provides +/// an interface to acquire data from a device. +/// It posts events the device may have as well as provides the state +/// \todo HAVE AN ABSTRACK BASE CLASS FOR THE DEVICE CLIENT +/// +class DeviceClient : public EventObject { public: - /// /// \brief Destructor /// - virtual ~DeviceClient() {} + virtual ~DeviceClient() = default; +public: /// /// \brief Get/Set the device IP /// @@ -77,27 +84,33 @@ public: /// const Quatd& getOrientation() const; - /// - /// \brief Get the status of the device buttons - /// - const std::map<size_t, bool>& getButtons() const; - - /// - /// \brief Get the status of a device button - /// - bool getButton(size_t buttonId) const; - /// /// \brief Get/Set the device force /// const Vec3d& getForce() const; void setForce(Vec3d force); -protected: + const std::unordered_map<int, int>& getButtons() const { return m_buttons; } /// - /// \brief Constructor + /// \brief Get the state of a button + /// returns 0 if can't find button /// + const int getButton(const int buttonId) const + { + if (m_buttons.find(buttonId) != m_buttons.end()) + { + return m_buttons.at(buttonId); + } + else + { + return 0; + } + } + + virtual void update() {} + +protected: DeviceClient(const std::string& name, const std::string& ip); std::string m_deviceName; ///< Device Name @@ -111,7 +124,8 @@ protected: Vec3d m_position; ///< Position of end effector Vec3d m_velocity; ///< Linear velocity of end effector Quatd m_orientation; ///< Orientation of the end effector - std::map<size_t, bool> m_buttons; ///< Buttons: true = pressed/false = not pressed Vec3d m_force; ///< Force vector + + std::unordered_map<int, int> m_buttons; }; } diff --git a/Source/Devices/imstkDummyClient.cpp b/Source/Devices/imstkDummyClient.cpp index f40d7de11494c09709ad9595fc39dbbdc6573d22..64635c910e9a8a7bbbd1b5b59d9ed0d0ecb93431 100644 --- a/Source/Devices/imstkDummyClient.cpp +++ b/Source/Devices/imstkDummyClient.cpp @@ -19,10 +19,7 @@ =========================================================================*/ -#include <map> - #include "imstkDummyClient.h" - #include "imstkLogger.h" namespace imstk diff --git a/Source/Devices/imstkDummyClient.h b/Source/Devices/imstkDummyClient.h index a21fcdeae125d2971f2552011880d24a80f75268..3027818028e87f82a3e2f92cdfd11e4eccc77d6a 100644 --- a/Source/Devices/imstkDummyClient.h +++ b/Source/Devices/imstkDummyClient.h @@ -23,6 +23,8 @@ #include "imstkDeviceClient.h" +#include <unordered_map> + namespace imstk { /// @@ -38,7 +40,7 @@ public: /// \brief Constructor/Destructor /// explicit DummyClient(const std::string& name) : DeviceClient(name, "localhost") {} - virtual ~DummyClient() {} + virtual ~DummyClient() override = default; protected: @@ -84,5 +86,8 @@ public: /// \brief Set the button status if it exists /// void setButton(const unsigned int buttonId, const bool buttonStatus); + +protected: + std::unordered_map<int, bool> m_buttons; }; } diff --git a/Source/Devices/imstkHDAPIDeviceClient.cpp b/Source/Devices/imstkHapticDeviceClient.cpp similarity index 81% rename from Source/Devices/imstkHDAPIDeviceClient.cpp rename to Source/Devices/imstkHapticDeviceClient.cpp index 654e22acd62afa36e2c73b704e284351705c4e5b..beac639ef00c9643ed2429d57fbe4669256eb366 100644 --- a/Source/Devices/imstkHDAPIDeviceClient.cpp +++ b/Source/Devices/imstkHapticDeviceClient.cpp @@ -19,25 +19,27 @@ =========================================================================*/ -#include "imstkHDAPIDeviceClient.h" +#include "imstkHapticDeviceClient.h" +#include "imstkLogger.h" -#include <HDU/hduVector.h> #include <HDU/hduError.h> - -#include "imstkLogger.h" +#include <HDU/hduVector.h> namespace imstk { void -HDAPIDeviceClient::init() +HapticDeviceClient::initialize() { - m_buttons = std::map<size_t, bool>{ { 0, false }, { 1, false }, { 2, false }, { 3, false } }; + m_buttons[0] = 0; + m_buttons[1] = 0; + m_buttons[2] = 0; + m_buttons[3] = 0; //flush error stack HDErrorInfo errorFlush; while (HD_DEVICE_ERROR(errorFlush = hdGetError())) {} - // Open Device + // Initialize the device m_handle = hdInitDevice(this->getDeviceName().c_str()); // If failed @@ -53,31 +55,38 @@ HDAPIDeviceClient::init() } void -HDAPIDeviceClient::run() +HapticDeviceClient::update() { hdScheduleSynchronous(hapticCallback, this, HD_MAX_SCHEDULER_PRIORITY); } void -HDAPIDeviceClient::cleanUp() +HapticDeviceClient::disable() { hdDisableDevice(m_handle); } HDCallbackCode HDCALLBACK -HDAPIDeviceClient::hapticCallback(void* pData) +HapticDeviceClient::hapticCallback(void* pData) { - auto client = reinterpret_cast<HDAPIDeviceClient*>(pData); - auto handle = client->m_handle; - auto state = client->m_state; + auto client = static_cast<HapticDeviceClient*>(pData); + HHD handle = client->m_handle; + HDstate state = client->m_state; + + if (handle == HD_BAD_HANDLE || handle == HD_INVALID_HANDLE) + { + return HD_CALLBACK_DONE; + } hdBeginFrame(handle); + hdMakeCurrentDevice(handle); hdSetDoublev(HD_CURRENT_FORCE, client->m_force.data()); hdGetDoublev(HD_CURRENT_POSITION, state.pos); hdGetDoublev(HD_CURRENT_VELOCITY, state.vel); hdGetDoublev(HD_CURRENT_TRANSFORM, state.trans); hdGetIntegerv(HD_CURRENT_BUTTONS, &state.buttons); + hdEndFrame(handle); client->m_position << state.pos[0], state.pos[1], state.pos[2]; @@ -88,6 +97,8 @@ HDAPIDeviceClient::hapticCallback(void* pData) client->m_buttons[2] = state.buttons & HD_DEVICE_BUTTON_3; client->m_buttons[3] = state.buttons & HD_DEVICE_BUTTON_4; + client->m_trackingEnabled = true; + return HD_CALLBACK_DONE; } } // imstk diff --git a/Source/Devices/imstkHDAPIDeviceClient.h b/Source/Devices/imstkHapticDeviceClient.h similarity index 69% rename from Source/Devices/imstkHDAPIDeviceClient.h rename to Source/Devices/imstkHapticDeviceClient.h index 525054168d34ed7d5a03656e4a8360dc0513b68c..ed9b11ff57fcc49d9d4e8e6c58eb671e5c702056 100644 --- a/Source/Devices/imstkHDAPIDeviceClient.h +++ b/Source/Devices/imstkHapticDeviceClient.h @@ -27,8 +27,9 @@ namespace imstk { -struct HD_state +struct HDstate { + // \todo pos are redundant? HDdouble pos[3]; HDdouble vel[3]; HDdouble trans[16]; @@ -38,35 +39,36 @@ struct HD_state /// /// \class HDAPIDeviceClient /// \brief Subclass of DeviceClient for phantom omni +/// Holds and updates the data sync or on its own thread +/// Holder of data /// -class HDAPIDeviceClient : public DeviceClient +class HapticDeviceClient : public DeviceClient { +friend class HapticDeviceManager; + public: + virtual ~HapticDeviceClient() {} +protected: /// - /// \brief Constructor/Destructor + /// \brief Constructor/Destructor, only the DeviceManager can construct /// - explicit HDAPIDeviceClient(const std::string& name) : DeviceClient(name, "localhost") {} - virtual ~HDAPIDeviceClient() {} - -protected: - - friend class HDAPIDeviceServer; + HapticDeviceClient(const std::string& name) : DeviceClient(name, "localhost"), m_handle(HD_INVALID_HANDLE) { } /// /// \brief Initialize the phantom omni device /// - void init(); + void initialize(); /// /// \brief Use callback to get tracking data from phantom omni /// - void run(); + void update() override; /// - /// \brief Closes the phantom omni device + /// \brief Disables the phantom omni device /// - void cleanUp(); + void disable(); private: /// @@ -74,7 +76,7 @@ private: /// static HDCallbackCode HDCALLBACK hapticCallback(void* pData); - HHD m_handle; ///< device handle - HD_state m_state; ///< device reading state + HHD m_handle; ///< device handle + HDstate m_state; ///< device reading state }; } diff --git a/Source/Devices/imstkHDAPIDeviceServer.cpp b/Source/Devices/imstkHapticDeviceManager.cpp similarity index 68% rename from Source/Devices/imstkHDAPIDeviceServer.cpp rename to Source/Devices/imstkHapticDeviceManager.cpp index 302d076e64a89ee3a20f9a7ab78a7050831ac009..08a45a5ea512b1b0f6c8711976164c3e76513d36 100644 --- a/Source/Devices/imstkHDAPIDeviceServer.cpp +++ b/Source/Devices/imstkHapticDeviceManager.cpp @@ -19,8 +19,8 @@ =========================================================================*/ -#include "imstkHDAPIDeviceServer.h" -#include "imstkHDAPIDeviceClient.h" +#include "imstkHapticDeviceManager.h" +#include "imstkHapticDeviceClient.h" #include <HD/hd.h> @@ -28,38 +28,37 @@ namespace imstk { -void -HDAPIDeviceServer::addDeviceClient(std::shared_ptr<HDAPIDeviceClient> client) +std::shared_ptr<HapticDeviceClient> +HapticDeviceManager::makeDeviceClient(const std::string& name) { - m_deviceClients.push_back(client); + auto deviceClient = std::shared_ptr<HapticDeviceClient>(new HapticDeviceClient(name)); + m_deviceClients.push_back(deviceClient); + return deviceClient; } void -HDAPIDeviceServer::initModule() +HapticDeviceManager::initialize() { for (const auto& client : m_deviceClients) { - client->init(); + client->initialize(); } - hdStartScheduler(); } void -HDAPIDeviceServer::runModule() +HapticDeviceManager::startThread() { - for (const auto& client : m_deviceClients) - { - client->run(); - } + initialize(); + hdStartScheduler(); } void -HDAPIDeviceServer::cleanUpModule() +HapticDeviceManager::stopThread() { hdStopScheduler(); for (const auto& client : m_deviceClients) { - client->cleanUp(); + client->disable(); } } } // imstk diff --git a/Source/Devices/imstkHDAPIDeviceServer.h b/Source/Devices/imstkHapticDeviceManager.h similarity index 57% rename from Source/Devices/imstkHDAPIDeviceServer.h rename to Source/Devices/imstkHapticDeviceManager.h index 0638b75dbd28e17ffb7b8cbad52f868bb09b4202..bc6dda73210389f03eebf80a335ab3059eca4a01 100644 --- a/Source/Devices/imstkHDAPIDeviceServer.h +++ b/Source/Devices/imstkHapticDeviceManager.h @@ -24,54 +24,53 @@ #include <vector> // imstk -#include "imstkModule.h" +#include "imstkThreadObject.h" namespace imstk { -class HDAPIDeviceClient; +class HapticDeviceClient; /// /// \class HDAPIDeviceServer -/// \brief Devices server using HDAPI +/// \brief Devices manager using HDAPI +/// \todo add the frame rate option for the servo loop /// -class HDAPIDeviceServer : public Module +class HapticDeviceManager : public ThreadObject { +friend HapticDeviceClient; + public: - /// - /// \brief Constructor - /// - HDAPIDeviceServer() : Module("HDAPIDeviceServer") - {} + HapticDeviceManager() : ThreadObject("HapticDeviceManager") {} /// /// \brief Destructor + /// Stop the scheduler /// - virtual ~HDAPIDeviceServer() {} + virtual ~HapticDeviceManager() override = default; /// - /// \brief Add device client + /// \brief Create a haptic device client and add it to the internal list /// - void addDeviceClient(std::shared_ptr<HDAPIDeviceClient> client); - -protected: + std::shared_ptr<HapticDeviceClient> makeDeviceClient(const std::string& name); /// - /// \brief Initialize the server module + /// \brief Initialize the client devices and start the scheduler /// - void initModule() override; + void initialize(); +protected: /// - /// \brief Run the server module + /// \brief /// - void runModule() override; + void startThread() override; /// - /// \brief Clean the server module + /// \brief /// - void cleanUpModule() override; + void stopThread() override; private: - std::vector<std::shared_ptr<HDAPIDeviceClient>> m_deviceClients; ///< list of OpenHaptics + std::vector<std::shared_ptr<HapticDeviceClient>> m_deviceClients; ///< list of all the device clients }; } // imstk diff --git a/Source/Devices/imstkKeyboardDeviceClient.cpp b/Source/Devices/imstkKeyboardDeviceClient.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b3c4e6a796574185e490145b0b301c97a3df745f --- /dev/null +++ b/Source/Devices/imstkKeyboardDeviceClient.cpp @@ -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. + +=========================================================================*/ + +#include "imstkKeyboardDeviceClient.h" + +namespace imstk +{ +std::shared_ptr<KeyboardDeviceClient> +KeyboardDeviceClient::New() +{ + return std::shared_ptr<KeyboardDeviceClient>(new KeyboardDeviceClient()); +} + +void +KeyboardDeviceClient::emitKeyDown(char key) +{ + const int prevKeyState = m_buttons[key]; + m_buttons[key] = KEY_PRESS; + if (prevKeyState != KEY_PRESS) + { + this->postEvent(KeyPressEvent(key, KEY_PRESS)); + } +} + +void +KeyboardDeviceClient::emitKeyUp(char key) +{ + const int prevKeyState = m_buttons[key]; + m_buttons[key] = KEY_RELEASE; + if (prevKeyState != KEY_RELEASE) + { + this->postEvent(KeyPressEvent(key, KEY_RELEASE)); + } +} + +bool +KeyboardDeviceClient::isKeyDown(const char key) const +{ + if (m_buttons.find(key) != m_buttons.end()) + { + return (m_buttons.at(key) == KEY_PRESS); + } + else + { + return false; + } +} +} \ No newline at end of file diff --git a/Source/Devices/imstkKeyboardDeviceClient.h b/Source/Devices/imstkKeyboardDeviceClient.h new file mode 100644 index 0000000000000000000000000000000000000000..07a3ddaf74f5409807ec960d405270e523b6b85d --- /dev/null +++ b/Source/Devices/imstkKeyboardDeviceClient.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. + +=========================================================================*/ + +#pragma once + +#include "imstkDeviceClient.h" + +#include <unordered_map> + +namespace imstk +{ +using KeyStateType = int; +#define KEY_RELEASE 0 +#define KEY_PRESS 1 + +class KeyPressEvent : public Event +{ +public: + KeyPressEvent(const char key, const KeyStateType keyPressType) : Event(EventType::KeyPress, 1), m_key(key), m_keyPressType(keyPressType) { } + virtual ~KeyPressEvent() override = default; + +public: + KeyStateType m_keyPressType; + const char m_key = -1; +}; + +/// +/// \class KeyboardDeviceClient +/// +/// \brief This class provides the keyboard state it also posts events +/// +class KeyboardDeviceClient : public DeviceClient +{ +protected: + /// + /// This object is only creatable through its New method + /// + KeyboardDeviceClient() : DeviceClient("KeyboardDevice", "") { } + + /// + /// This object is only creatable through this method + /// + static std::shared_ptr<KeyboardDeviceClient> New(); + +public: + virtual ~KeyboardDeviceClient() override = default; + + // Only these classes may provide this object + friend class VTKInteractorStyle; + friend class ConsoleThread; + +public: + const std::unordered_map<int, KeyStateType>& getKeyState() const { return m_buttons; } + +protected: + /// + /// \brief Post a key press + /// + void emitKeyDown(char key); + + /// + /// \brief Post a key release + /// + void emitKeyUp(char key); + + /// + /// \brief Returns true if key is currently down + /// + bool isKeyDown(const char key) const; +}; +} \ No newline at end of file diff --git a/Source/SimulationManager/imstkInteractorStyle.cpp b/Source/Devices/imstkMouseDeviceClient.cpp similarity index 83% rename from Source/SimulationManager/imstkInteractorStyle.cpp rename to Source/Devices/imstkMouseDeviceClient.cpp index 1dd332a987a536693c1c381ede0ef7ff5e8be179..e44c94380debfb356afb25b587a0140a4fc21a56 100644 --- a/Source/SimulationManager/imstkInteractorStyle.cpp +++ b/Source/Devices/imstkMouseDeviceClient.cpp @@ -19,8 +19,13 @@ =========================================================================*/ -#include "imstkInteractorStyle.h" +#include "imstkMouseDeviceClient.h" namespace imstk { +std::shared_ptr<MouseDeviceClient> +MouseDeviceClient::New() +{ + return std::shared_ptr<MouseDeviceClient>(new MouseDeviceClient()); +} } \ No newline at end of file diff --git a/Source/Devices/imstkMouseDeviceClient.h b/Source/Devices/imstkMouseDeviceClient.h new file mode 100644 index 0000000000000000000000000000000000000000..3d177c8446857459c7c8739cf01a551399d12625 --- /dev/null +++ b/Source/Devices/imstkMouseDeviceClient.h @@ -0,0 +1,159 @@ +/*========================================================================= + + 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 "imstkDeviceClient.h" + +#include <unordered_map> + +namespace imstk +{ +using MouseActionType = int; +#define MOUSE_RELEASE 0 +#define MOUSE_PRESS 1 +#define MOUSE_SCROLL 2 +#define MOUSE_MOVE 3 + +using MouseButtonType = int; +#define LEFT_BUTTON 0 +#define RIGHT_BUTTON 1 +#define MIDDLE_BUTTON 2 + +class MouseEvent : public Event +{ +public: + MouseEvent(const MouseActionType mouseActionType, const MouseButtonType buttonId) : + Event(EventType::MouseEvent, 1), + m_mouseActionType(mouseActionType), m_buttonId(buttonId), m_scrollDx(0.0) + { + } + + MouseEvent(const MouseActionType mouseActionType, const double scrollDx) : + Event(EventType::MouseEvent, 1), + m_mouseActionType(mouseActionType), m_scrollDx(scrollDx), m_buttonId(0) + { + } + + MouseEvent(const MouseActionType mouseActionType) : + Event(EventType::MouseEvent, 1), + m_mouseActionType(mouseActionType), m_scrollDx(0.0), m_buttonId(0) + { + } + + virtual ~MouseEvent() override = default; + +public: + MouseActionType m_mouseActionType; + double m_scrollDx; ///> Mouse scroll + MouseButtonType m_buttonId; ///> Button id +}; + +/// +/// \class KeyboardDeviceClient +/// +/// \brief This class provides the keyboard state it also posts button events +/// +class MouseDeviceClient : public DeviceClient +{ +protected: + /// + /// This object is only creatable through its New method + /// + MouseDeviceClient() : DeviceClient("MouseDevice", ""), + m_pos(Vec2d(0.0, 0.0)), m_prevPos(Vec2d(0.0, 0.0)) { } + + /// + /// This object is only creatable through this method + /// + static std::shared_ptr<MouseDeviceClient> New(); + +public: + virtual ~MouseDeviceClient() override = default; + + // Only the viewer is allowed to provide these objects + friend class VTKInteractorStyle; + +public: + /// + /// \brief Get the current position of the mouse + /// + const Vec2d& getPos() const { return m_pos; } + + /// + /// \brief Get the previous position of the mouse + /// + const Vec2d& getPrevPos() const { return m_prevPos; } + + /// + /// \brief Query if the button is down + /// + const bool isButtonDown(const MouseButtonType buttonId) const + { + if (m_buttons.find(buttonId) != m_buttons.end()) + { + return m_buttons.at(buttonId) == MOUSE_PRESS; + } + else + { + return MOUSE_RELEASE; + } + } + +protected: + /// + /// \brief Update the mouse position + /// + void updateMousePos(const Vec2d& pos) + { + m_prevPos = m_pos; + m_pos = pos; + this->postEvent(MouseEvent(MOUSE_MOVE)); + } + + /// + /// \brief Post a click down event + /// + void emitButtonPress(const MouseButtonType buttonId) + { + m_buttons[buttonId] = MOUSE_PRESS; + this->postEvent(MouseEvent(MOUSE_PRESS, buttonId)); + } + + /// + /// \brief Post a click release event + /// + void emitButtonRelease(const MouseButtonType buttonId) + { + m_buttons[buttonId] = MOUSE_RELEASE; + this->postEvent(MouseEvent(MOUSE_RELEASE, buttonId)); + } + + /// + /// \brief Post a mouse scroll event + /// + void emitScroll(const double dx) { this->postEvent(MouseEvent(MOUSE_SCROLL, dx)); } + +protected: + Vec2d m_prevPos; + Vec2d m_pos; +}; +} \ No newline at end of file diff --git a/Source/Devices/imstkOpenVRDeviceClient.cpp b/Source/Devices/imstkOpenVRDeviceClient.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6605e0a3d642b1822ac9ac07662b0f69f361c9ea --- /dev/null +++ b/Source/Devices/imstkOpenVRDeviceClient.cpp @@ -0,0 +1,75 @@ +/*========================================================================= + + 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 "imstkOpenVRDeviceClient.h" + +namespace imstk +{ +std::shared_ptr<OpenVRDeviceClient> +OpenVRDeviceClient::New(VRDeviceType deviceType) +{ + return std::shared_ptr<OpenVRDeviceClient>(new OpenVRDeviceClient(deviceType)); +} + +void +OpenVRDeviceClient::emitButtonTouched(const int buttonId) +{ + const int prevButtonState = m_buttons[buttonId]; + m_buttons[buttonId] = BUTTON_TOUCHED; + if (prevButtonState != BUTTON_TOUCHED) + { + this->postEvent(VRButtonEvent(buttonId, BUTTON_TOUCHED)); + } +} + +void +OpenVRDeviceClient::emitButtonUntouched(const int buttonId) +{ + const int prevButtonState = m_buttons[buttonId]; + m_buttons[buttonId] = BUTTON_UNTOUCHED; + if (prevButtonState != BUTTON_UNTOUCHED) + { + this->postEvent(VRButtonEvent(buttonId, BUTTON_UNTOUCHED)); + } +} + +void +OpenVRDeviceClient::emitButtonPress(const int buttonId) +{ + const int prevButtonState = m_buttons[buttonId]; + m_buttons[buttonId] = BUTTON_PRESSED; + if (prevButtonState != BUTTON_PRESSED) + { + this->postEvent(VRButtonEvent(buttonId, BUTTON_PRESSED)); + } +} + +void +OpenVRDeviceClient::emitButtonRelease(const int buttonId) +{ + const int prevButtonState = m_buttons[buttonId]; + m_buttons[buttonId] = BUTTON_RELEASED; + if (prevButtonState != BUTTON_RELEASED) + { + this->postEvent(VRButtonEvent(buttonId, BUTTON_RELEASED)); + } +} +} \ No newline at end of file diff --git a/Source/Devices/imstkOpenVRDeviceClient.h b/Source/Devices/imstkOpenVRDeviceClient.h new file mode 100644 index 0000000000000000000000000000000000000000..42aa17b13bc98771e690de7af136edae8f423bc4 --- /dev/null +++ b/Source/Devices/imstkOpenVRDeviceClient.h @@ -0,0 +1,110 @@ +/*========================================================================= + + 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 "imstkDeviceClient.h" + +#include <unordered_map> + +class vtkInteractorStyleVR; + +namespace imstk +{ +using VRDeviceType = int; +#define OPENVR_LEFT_CONTROLLER 0 +#define OPENVR_RIGHT_CONTROLLER 1 +#define OPENVR_HMD 2 + +using VRButtonStateType = int; +#define BUTTON_RELEASED 0 +#define BUTTON_TOUCHED 1 +#define BUTTON_UNTOUCHED 2 +#define BUTTON_PRESSED 3 + +class VRButtonEvent : public Event +{ +public: + VRButtonEvent(const int button, const VRButtonStateType keyPressType) : Event(EventType::VRButtonPress, 1), + m_buttonState(keyPressType), + m_button(button) + { + } + + virtual ~VRButtonEvent() override = default; + +public: + VRButtonStateType m_buttonState; + const int m_button = -1; +}; + +/// +/// \class OpenVRDeviceClient +/// +/// \brief This class provides quantities for the specified VR device +/// The devices creation is tied to the viewer. It is only acquirable +/// from a VR viewer and exists on the viewers thread. +/// +class OpenVRDeviceClient : public DeviceClient +{ +protected: + /// + /// This object is only creatable through its New method + /// + OpenVRDeviceClient(VRDeviceType deviceType) : DeviceClient("OpenVRDevice", ""), + m_deviceType(deviceType) { } + + /// + /// This object is only creatable through this method + /// + static std::shared_ptr<OpenVRDeviceClient> New(VRDeviceType deviceType); + +public: + virtual ~OpenVRDeviceClient() override = default; + + // Only the viewer is allowed to provide these objects + friend class ::vtkInteractorStyleVR; + +public: + VRDeviceType getDeviceType() const { return m_deviceType; } + + /// + /// \brief Set the current position and orientation + /// + void setPose(const Vec3d& pos, const Quatd& orientation) + { + m_trackingEnabled = true; + m_position = pos; + m_orientation = orientation; + } + +protected: + /// + /// \brief Emit various button events + /// + void emitButtonTouched(const int buttonId); + void emitButtonUntouched(const int buttonId); + void emitButtonPress(const int buttonId); + void emitButtonRelease(const int buttonId); + +private: + VRDeviceType m_deviceType; +}; +} \ No newline at end of file diff --git a/Source/Devices/imstkVRPNArduinoDeviceClient.cpp b/Source/Devices/imstkVRPNArduinoDeviceClient.cpp index f496cd9b6f6b44a871c04fe3dcb9be961915709c..d6f61980b7ec5091ed7350ddcbdee34ec686a5a3 100644 --- a/Source/Devices/imstkVRPNArduinoDeviceClient.cpp +++ b/Source/Devices/imstkVRPNArduinoDeviceClient.cpp @@ -21,12 +21,10 @@ #include "imstkVRPNArduinoDeviceClient.h" -#include "imstkLogger.h" - namespace imstk { void -VRPNArduinoDeviceClient::initModule() +VRPNArduinoDeviceClient::initThread() { auto fullDeviceIp = this->getName().c_str(); @@ -36,13 +34,13 @@ VRPNArduinoDeviceClient::initModule() } void -VRPNArduinoDeviceClient::runModule() +VRPNArduinoDeviceClient::updateThread() { m_vrpnAnalog->mainloop(); } void -VRPNArduinoDeviceClient::cleanUpModule() +VRPNArduinoDeviceClient::stopThread() { //Module cleanup is causing TCP errors - seems to work fine without it //m_vrpnAnalog->unregister_change_handler(this, analogChangeHandler); diff --git a/Source/Devices/imstkVRPNArduinoDeviceClient.h b/Source/Devices/imstkVRPNArduinoDeviceClient.h index 728d2e53ddf06b86da07fa8b7cf7fc02d0d21272..dd51806eac111cf6bf403e6a4b4ac8a18781a311 100644 --- a/Source/Devices/imstkVRPNArduinoDeviceClient.h +++ b/Source/Devices/imstkVRPNArduinoDeviceClient.h @@ -22,7 +22,7 @@ #pragma once #include "imstkDeviceClient.h" -#include "imstkModule.h" +#include "imstkLoopThreadObject.h" #include <vrpn_Configure.h> #include <vrpn_Analog.h> @@ -33,7 +33,7 @@ namespace imstk /// \class VRPNDeviceClient /// \brief Subclass of DeviceClient using VRPN /// -class VRPNArduinoDeviceClient : public DeviceClient, public Module +class VRPNArduinoDeviceClient : public DeviceClient, public LoopThreadObject { public: @@ -42,7 +42,7 @@ public: /// VRPNArduinoDeviceClient(const std::string& deviceName, const std::string& ip) : DeviceClient(deviceName, ip), - Module(deviceName + "@" + ip), + LoopThreadObject(deviceName + "@" + ip), m_ypr(Vec3d::Zero()), m_accel(Vec3d::Zero()), m_roll(0) {} @@ -50,8 +50,7 @@ public: /// /// \brief Destructor /// - virtual ~VRPNArduinoDeviceClient() - {} + virtual ~VRPNArduinoDeviceClient() override = default; /// /// \brief Get YPR @@ -72,17 +71,17 @@ protected: /// /// \brief Initialize device client module /// - void initModule() override; + void initThread() override; /// /// \brief Run the device client /// - void runModule() override; + void updateThread() override; /// - /// \brief Clean the device client module + /// \brief Clean the device client /// - void cleanUpModule() override; + void stopThread() override; private: diff --git a/Source/Devices/imstkVRPNDeviceClient.cpp b/Source/Devices/imstkVRPNDeviceClient.cpp index 0d5ced48ec561206056e51c4ba2089d402894064..c4c04d3ffd4171aec598ea046044f077a1bfa43e 100644 --- a/Source/Devices/imstkVRPNDeviceClient.cpp +++ b/Source/Devices/imstkVRPNDeviceClient.cpp @@ -20,13 +20,12 @@ =========================================================================*/ #include "imstkVRPNDeviceClient.h" - #include "imstkLogger.h" namespace imstk { void -VRPNDeviceClient::initModule() +VRPNDeviceClient::initThread() { auto fullDeviceIp = this->getName().c_str(); @@ -47,7 +46,7 @@ VRPNDeviceClient::initModule() } void -VRPNDeviceClient::runModule() +VRPNDeviceClient::updateThread() { if (this->getTrackingEnabled()) { @@ -70,7 +69,7 @@ VRPNDeviceClient::runModule() } void -VRPNDeviceClient::cleanUpModule() +VRPNDeviceClient::stopThread() { m_vrpnTracker->unregister_change_handler(this, trackerChangeHandler); m_vrpnTracker->unregister_change_handler(this, velocityChangeHandler); diff --git a/Source/Devices/imstkVRPNDeviceClient.h b/Source/Devices/imstkVRPNDeviceClient.h index ef641fecab24939268b4dbebe387a26259c768b1..b58958ec17e3a627b59066a127dc7d12ccc8b78d 100644 --- a/Source/Devices/imstkVRPNDeviceClient.h +++ b/Source/Devices/imstkVRPNDeviceClient.h @@ -22,14 +22,14 @@ #pragma once #include "imstkDeviceClient.h" -#include "imstkModule.h" +#include "imstkLoopThreadObject.h" -// vrpn includes #include <vrpn_Configure.h> #include <vrpn_Tracker.h> #include <vrpn_Analog.h> #include <vrpn_Button.h> #include <vrpn_ForceDevice.h> +#include <unordered_map> namespace imstk { @@ -37,7 +37,7 @@ namespace imstk /// \class VRPNDeviceClient /// \brief Subclass of DeviceClient using VRPN /// -class VRPNDeviceClient : public DeviceClient, public Module +class VRPNDeviceClient : public DeviceClient, public LoopThreadObject { public: @@ -46,30 +46,29 @@ public: /// VRPNDeviceClient(const std::string& deviceName, const std::string& ip) : DeviceClient(deviceName, ip), - Module(deviceName + "@" + ip) + LoopThreadObject(deviceName + "@" + ip) {} /// /// \brief Destructor /// - virtual ~VRPNDeviceClient() - {} + virtual ~VRPNDeviceClient() override = default; protected: /// /// \brief Initialize device client module /// - void initModule() override; + void initThread() override; /// /// \brief Run the device client /// - void runModule() override; + void updateThread() override; /// - /// \brief Clean the device client module + /// \brief Clean the device client /// - void cleanUpModule() override; + void stopThread() override; private: @@ -120,5 +119,8 @@ private: std::shared_ptr<vrpn_Analog_Remote> m_vrpnAnalog; //!< VRPN position/orientation interface std::shared_ptr<vrpn_Button_Remote> m_vrpnButton; //!< VRPN button interface std::shared_ptr<vrpn_ForceDevice_Remote> m_vrpnForceDevice; //!< VRPN force interface + +public: + std::unordered_map<int, bool> m_buttons; }; } diff --git a/Source/Devices/imstkVRPNDeviceServer.cpp b/Source/Devices/imstkVRPNDeviceServer.cpp index 61f56718ee10706d84a1f8ad0e33fb882c8506e2..670ea57d0de754da66f203dad5f8eef0bd703604 100644 --- a/Source/Devices/imstkVRPNDeviceServer.cpp +++ b/Source/Devices/imstkVRPNDeviceServer.cpp @@ -20,17 +20,16 @@ =========================================================================*/ #include "imstkVRPNDeviceServer.h" +#include "imstkLogger.h" -#include "vrpn_3DConnexion.h" -#include "vrpn_Tracker_NovintFalcon.h" -#include "vrpn_Tracker_OSVRHackerDevKit.h" -#include "vrpn_Streaming_Arduino.h" +#include <vrpn_3DConnexion.h> +#include <vrpn_Streaming_Arduino.h> +#include <vrpn_Tracker_NovintFalcon.h> +#include <vrpn_Tracker_OSVRHackerDevKit.h> #ifdef VRPN_USE_PHANTOM_SERVER - #include "vrpn_Phantom.h" + #include <vrpn_Phantom.h> #endif -#include "imstkLogger.h" - namespace imstk { void @@ -57,7 +56,7 @@ VRPNDeviceServer::addSerialDevice(const std::string& deviceName, DeviceType devi } void -VRPNDeviceServer::initModule() +VRPNDeviceServer::initThread() { std::string ip = m_machine + ":" + std::to_string(m_port); m_serverConnection = vrpn_create_server_connection(ip.c_str()); @@ -120,14 +119,14 @@ VRPNDeviceServer::initModule() } void -VRPNDeviceServer::runModule() +VRPNDeviceServer::updateThread() { m_serverConnection->mainloop(); m_deviceConnections->mainloop(); } void -VRPNDeviceServer::cleanUpModule() +VRPNDeviceServer::stopThread() { m_deviceConnections->clear(); delete(m_deviceConnections); diff --git a/Source/Devices/imstkVRPNDeviceServer.h b/Source/Devices/imstkVRPNDeviceServer.h index ea36587b654fef45adb9f0f7af9aebd8e6466aa2..80d4689fc3f6163575dc95dc34349fe065fb3ab7 100644 --- a/Source/Devices/imstkVRPNDeviceServer.h +++ b/Source/Devices/imstkVRPNDeviceServer.h @@ -21,17 +21,14 @@ #pragma once -#include <vector> +#include "imstkLoopThreadObject.h" + #include <map> #include <string> -// vrpn #include <vrpn_Connection.h> #include <vrpn_MainloopContainer.h> -// imstk -#include "imstkModule.h" - namespace imstk { /// @@ -51,7 +48,7 @@ enum class DeviceType /// \class VRPNDeviceServer /// \brief Devices server using VRPN /// -class VRPNDeviceServer : public Module +class VRPNDeviceServer : public LoopThreadObject { public: @@ -61,13 +58,13 @@ public: VRPNDeviceServer(const std::string& machine = "localhost", int port = vrpn_DEFAULT_LISTEN_PORT_NO) : m_machine(machine), m_port(port), - Module(machine + ":" + std::to_string(port)) + LoopThreadObject(machine + ":" + std::to_string(port)) {} /// /// \brief Destructor /// - virtual ~VRPNDeviceServer() {} + virtual ~VRPNDeviceServer() override = default; /// /// \brief Add device @@ -84,17 +81,17 @@ protected: /// /// \brief Initialize the server module /// - void initModule() override; + void initThread() override; /// /// \brief Run the server module /// - void runModule() override; + void updateThread() override; /// /// \brief Clean the server module /// - void cleanUpModule() override; + void stopThread() override; private: diff --git a/Source/DynamicalModels/InternalForceModel/imstkCorotationalFEMForceModel.cpp b/Source/DynamicalModels/InternalForceModel/imstkCorotationalFEMForceModel.cpp index f0e6c5046cf91fc045bb9d3844e9f35194f20ec4..ebf8ba01778d38c67dbb407bf451b844c3d77fbf 100644 --- a/Source/DynamicalModels/InternalForceModel/imstkCorotationalFEMForceModel.cpp +++ b/Source/DynamicalModels/InternalForceModel/imstkCorotationalFEMForceModel.cpp @@ -23,8 +23,7 @@ #pragma warning( push ) #pragma warning( disable : 4458 ) -//vega -#include "corotationalLinearFEM.h" +#include <corotationalLinearFEM.h> #pragma warning( pop ) namespace imstk diff --git a/Source/DynamicalModels/InternalForceModel/imstkCorotationalFEMForceModel.h b/Source/DynamicalModels/InternalForceModel/imstkCorotationalFEMForceModel.h index bd9337ba0e05a228bfef1e051b9c5148a7226f86..075e289d8cfdc990574e80c668f68fbf36243252 100644 --- a/Source/DynamicalModels/InternalForceModel/imstkCorotationalFEMForceModel.h +++ b/Source/DynamicalModels/InternalForceModel/imstkCorotationalFEMForceModel.h @@ -21,7 +21,6 @@ #pragma once -//imstk #include "imstkInternalForceModel.h" namespace vega diff --git a/Source/DynamicalModels/InternalForceModel/imstkInternalForceModel.h b/Source/DynamicalModels/InternalForceModel/imstkInternalForceModel.h index 09fc5adf65107e09dbf3493005538ac9c90f11da..fd438a6d7a8346e20859aa5a1d43da60fa3e3fdd 100644 --- a/Source/DynamicalModels/InternalForceModel/imstkInternalForceModel.h +++ b/Source/DynamicalModels/InternalForceModel/imstkInternalForceModel.h @@ -24,12 +24,15 @@ #include "imstkMath.h" #include "imstkInternalForceModelTypes.h" +#ifdef WIN32 #pragma warning( push ) #pragma warning( disable : 4458 ) #pragma warning( disable : 4100 ) -//vega -#include "forceModel.h" +#endif +#include <forceModel.h> +#ifdef WIN32 #pragma warning( pop ) +#endif namespace imstk { @@ -45,7 +48,7 @@ public: /// /// \brief Constructor /// - InternalForceModel() {}; + InternalForceModel() = default; /// /// \brief Destructor diff --git a/Source/DynamicalModels/InternalForceModel/imstkIsotropicHyperelasticFEMForceModel.cpp b/Source/DynamicalModels/InternalForceModel/imstkIsotropicHyperelasticFEMForceModel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cd89622445176b7cb502441abba5505157b67b65 --- /dev/null +++ b/Source/DynamicalModels/InternalForceModel/imstkIsotropicHyperelasticFEMForceModel.cpp @@ -0,0 +1,74 @@ +/*= ======================================================================== + +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 permissionsand +limitations under the License. + +======================================================================== = */ + +#include "imstkIsotropicHyperelasticFEMForceModel.h" +#include "imstkLogger.h" + +#include <MooneyRivlinIsotropicMaterial.h> +#include <neoHookeanIsotropicMaterial.h> +#include <StVKIsotropicMaterial.h> + +namespace imstk +{ +IsotropicHyperelasticFEForceModel::IsotropicHyperelasticFEForceModel(const HyperElasticMaterialType materialType, + std::shared_ptr<vega::VolumetricMesh> mesh, + const double inversionThreshold, const bool withGravity, const double gravity) : InternalForceModel() +{ + auto tetMesh = std::dynamic_pointer_cast<vega::TetMesh>(mesh); + + const int enableCompressionResistance = 1; + const double compressionResistance = 500; + switch (materialType) + { + case HyperElasticMaterialType::StVK: + m_isotropicMaterial = std::make_shared<vega::StVKIsotropicMaterial>( + tetMesh.get(), + enableCompressionResistance, + compressionResistance); + break; + + case HyperElasticMaterialType::NeoHookean: + m_isotropicMaterial = std::make_shared<vega::NeoHookeanIsotropicMaterial>( + tetMesh.get(), + enableCompressionResistance, + compressionResistance); + break; + + case HyperElasticMaterialType::MooneyRivlin: + m_isotropicMaterial = std::make_shared<vega::MooneyRivlinIsotropicMaterial>( + tetMesh.get(), + enableCompressionResistance, + compressionResistance); + break; + + default: + LOG(WARNING) << "Error: Invalid hyperelastic material type."; + break; + } + + m_isotropicHyperelasticFEM = std::make_shared<vega::IsotropicHyperelasticFEM>( + tetMesh.get(), + m_isotropicMaterial.get(), + inversionThreshold, + withGravity, + gravity); +} +} \ No newline at end of file diff --git a/Source/DynamicalModels/InternalForceModel/imstkIsotropicHyperelasticFEMForceModel.h b/Source/DynamicalModels/InternalForceModel/imstkIsotropicHyperelasticFEMForceModel.h index 296976ae988746416e2da9bc8aa13b18b765ddf4..1c5dad668c433f2784e4da8c50c36b7c29328e5e 100644 --- a/Source/DynamicalModels/InternalForceModel/imstkIsotropicHyperelasticFEMForceModel.h +++ b/Source/DynamicalModels/InternalForceModel/imstkIsotropicHyperelasticFEMForceModel.h @@ -21,20 +21,16 @@ #pragma once -#include <g3log/g3log.hpp> - -//imstk #include "imstkInternalForceModel.h" -//vega +#ifdef WIN32 #pragma warning( push ) #pragma warning( disable : 4458 ) -#include "isotropicHyperelasticFEM.h" +#endif +#include <isotropicHyperelasticFEM.h> +#ifdef WIN32 #pragma warning( pop ) - -#include "StVKIsotropicMaterial.h" -#include "neoHookeanIsotropicMaterial.h" -#include "MooneyRivlinIsotropicMaterial.h" +#endif namespace imstk { @@ -53,46 +49,7 @@ public: std::shared_ptr<vega::VolumetricMesh> mesh, const double inversionThreshold, const bool withGravity = true, - const double gravity = 10.0) : InternalForceModel() - { - auto tetMesh = std::dynamic_pointer_cast<vega::TetMesh>(mesh); - - const int enableCompressionResistance = 1; - const double compressionResistance = 500; - switch (materialType) - { - case HyperElasticMaterialType::StVK: - m_isotropicMaterial = std::make_shared<vega::StVKIsotropicMaterial>( - tetMesh.get(), - enableCompressionResistance, - compressionResistance); - break; - - case HyperElasticMaterialType::NeoHookean: - m_isotropicMaterial = std::make_shared<vega::NeoHookeanIsotropicMaterial>( - tetMesh.get(), - enableCompressionResistance, - compressionResistance); - break; - - case HyperElasticMaterialType::MooneyRivlin: - m_isotropicMaterial = std::make_shared<vega::MooneyRivlinIsotropicMaterial>( - tetMesh.get(), - enableCompressionResistance, - compressionResistance); - break; - - default: - LOG(WARNING) << "Error: Invalid hyperelastic material type."; - } - - m_isotropicHyperelasticFEM = std::make_shared<vega::IsotropicHyperelasticFEM>( - tetMesh.get(), - m_isotropicMaterial.get(), - inversionThreshold, - withGravity, - gravity); - } + const double gravity = 10.0); /// /// \brief Constructor type that is not allowed @@ -102,7 +59,7 @@ public: /// /// \brief Destructor /// - virtual ~IsotropicHyperelasticFEForceModel() = default; + virtual ~IsotropicHyperelasticFEForceModel() override = default; /// /// \brief Get the internal force diff --git a/Source/DynamicalModels/InternalForceModel/imstkLinearFEMForceModel.cpp b/Source/DynamicalModels/InternalForceModel/imstkLinearFEMForceModel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b0e435f1f4aea1e679262e3e41e413bdbbd4db87 --- /dev/null +++ b/Source/DynamicalModels/InternalForceModel/imstkLinearFEMForceModel.cpp @@ -0,0 +1,58 @@ +/*========================================================================= + + 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 "imstkLinearFEMForceModel.h" + +#include <StVKElementABCDLoader.h> +#include <StVKStiffnessMatrix.h> +#include <tetMesh.h> + +namespace imstk +{ +LinearFEMForceModel::LinearFEMForceModel(std::shared_ptr<vega::VolumetricMesh> mesh, + const bool withGravity, const double gravity) : InternalForceModel() +{ + auto tetMesh = std::dynamic_pointer_cast<vega::TetMesh>(mesh); + + vega::StVKElementABCD* precomputedIntegrals = vega::StVKElementABCDLoader::load(tetMesh.get()); + m_stVKInternalForces = std::make_shared<vega::StVKInternalForces>(tetMesh.get(), precomputedIntegrals, withGravity, gravity); + + auto stVKStiffnessMatrix = std::make_shared<vega::StVKStiffnessMatrix>(m_stVKInternalForces.get()); + + stVKStiffnessMatrix->GetStiffnessMatrixTopology(&m_stiffnessMatrixRawPtr); + std::shared_ptr<vega::SparseMatrix> m_stiffnessMatrix2(m_stiffnessMatrixRawPtr); + m_stiffnessMatrix = m_stiffnessMatrix2; + + auto K = m_stiffnessMatrix.get(); + stVKStiffnessMatrix->GetStiffnessMatrixTopology(&K); + double* zero = (double*)calloc(m_stiffnessMatrix->GetNumRows(), sizeof(double)); + stVKStiffnessMatrix->ComputeStiffnessMatrix(zero, m_stiffnessMatrix.get()); + free(zero); +}; + +LinearFEMForceModel::~LinearFEMForceModel() +{ + if (m_stiffnessMatrixRawPtr) + { + delete m_stiffnessMatrixRawPtr; + } +} +} \ No newline at end of file diff --git a/Source/DynamicalModels/InternalForceModel/imstkLinearFEMForceModel.h b/Source/DynamicalModels/InternalForceModel/imstkLinearFEMForceModel.h index 28ebf8c784f188a446bf5cea009800835c4a71ed..14c961ef644f383e0c9aaee404904059872cb4b9 100644 --- a/Source/DynamicalModels/InternalForceModel/imstkLinearFEMForceModel.h +++ b/Source/DynamicalModels/InternalForceModel/imstkLinearFEMForceModel.h @@ -21,14 +21,13 @@ #pragma once -//imstk #include "imstkInternalForceModel.h" -#include "imstkLogger.h" -//vega -#include "StVKInternalForces.h" -#include "StVKStiffnessMatrix.h" -#include "StVKElementABCDLoader.h" +namespace vega +{ +class StVKInternalForces; +class VolumetricMesh; +} namespace imstk { @@ -44,37 +43,12 @@ public: /// \brief Constructor /// LinearFEMForceModel(std::shared_ptr<vega::VolumetricMesh> mesh, - const bool withGravity = true, - const double gravity = -9.81) : InternalForceModel() - { - auto tetMesh = std::dynamic_pointer_cast<vega::TetMesh>(mesh); - - vega::StVKElementABCD* precomputedIntegrals = vega::StVKElementABCDLoader::load(tetMesh.get()); - m_stVKInternalForces = std::make_shared<vega::StVKInternalForces>(tetMesh.get(), precomputedIntegrals, withGravity, gravity); - - auto stVKStiffnessMatrix = std::make_shared<vega::StVKStiffnessMatrix>(m_stVKInternalForces.get()); - - stVKStiffnessMatrix->GetStiffnessMatrixTopology(&m_stiffnessMatrixRawPtr); - std::shared_ptr<vega::SparseMatrix> m_stiffnessMatrix2(m_stiffnessMatrixRawPtr); - m_stiffnessMatrix = m_stiffnessMatrix2; - - auto K = m_stiffnessMatrix.get(); - stVKStiffnessMatrix->GetStiffnessMatrixTopology(&K); - double* zero = (double*)calloc(m_stiffnessMatrix->GetNumRows(), sizeof(double)); - stVKStiffnessMatrix->ComputeStiffnessMatrix(zero, m_stiffnessMatrix.get()); - free(zero); - }; + const bool withGravity = true, const double gravity = -9.81); /// /// \brief Destructor /// - virtual ~LinearFEMForceModel() - { - if (m_stiffnessMatrixRawPtr) - { - delete m_stiffnessMatrixRawPtr; - } - }; + virtual ~LinearFEMForceModel() override; /// /// \brief Compute the internal force @@ -85,8 +59,10 @@ public: m_stiffnessMatrix->MultiplyVector(data, internalForce.data()); } +#ifdef WIN32 #pragma warning( push ) #pragma warning( disable : 4100 ) +#endif /// /// \brief Get the tangent stiffness matrix /// \todo Clear warning C4100 @@ -96,7 +72,9 @@ public: InternalForceModel::updateValuesFromMatrix(m_stiffnessMatrix, tangentStiffnessMatrix.valuePtr()); } +#ifdef WIN32 #pragma warning( pop ) +#endif /// /// \brief Get the tangent stiffness matrix topology diff --git a/Source/DynamicalModels/InternalForceModel/imstkStVKForceModel.cpp b/Source/DynamicalModels/InternalForceModel/imstkStVKForceModel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2e67ace5a7c201c3bb4d6d24d4aff050d452f57d --- /dev/null +++ b/Source/DynamicalModels/InternalForceModel/imstkStVKForceModel.cpp @@ -0,0 +1,37 @@ +/*========================================================================= + + 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 "imstkStVKForceModel.h" + +#include <StVKElementABCDLoader.h> +#include <tetMesh.h> + +namespace imstk +{ +StVKForceModel::StVKForceModel(std::shared_ptr<vega::VolumetricMesh> mesh, + const bool withGravity, const double gravity) : InternalForceModel() +{ + auto tetMesh = std::dynamic_pointer_cast<vega::TetMesh>(mesh); + vega::StVKElementABCD* precomputedIntegrals = vega::StVKElementABCDLoader::load(tetMesh.get()); + m_stVKInternalForces = std::make_shared<vega::StVKInternalForces>(tetMesh.get(), precomputedIntegrals, withGravity, gravity); + m_vegaStVKStiffnessMatrix = std::make_shared<vega::StVKStiffnessMatrix>(m_stVKInternalForces.get()); +} +} \ No newline at end of file diff --git a/Source/DynamicalModels/InternalForceModel/imstkStVKForceModel.h b/Source/DynamicalModels/InternalForceModel/imstkStVKForceModel.h index dbd5837d25874ecdab899c9cd8ac2b4c409b0b92..1f17a0f3ff09f1de5be09660943dda3b733e5db1 100644 --- a/Source/DynamicalModels/InternalForceModel/imstkStVKForceModel.h +++ b/Source/DynamicalModels/InternalForceModel/imstkStVKForceModel.h @@ -21,19 +21,15 @@ #pragma once -//imstk #include "imstkInternalForceModel.h" -#include "imstkLogger.h" -//vega -#pragma warning( push ) -#pragma warning( disable : 4458 ) -#include "StVKInternalForces.h" -#pragma warning( pop ) +#include <StVKStiffnessMatrix.h> -#include "StVKStiffnessMatrix.h" -#include "StVKElementABCDLoader.h" -#include "tetMesh.h" +namespace vega +{ +class StVKInternalForces; +class VolumetricMesh; +} namespace imstk { @@ -44,19 +40,12 @@ public: /// \brief Constructor /// StVKForceModel(std::shared_ptr<vega::VolumetricMesh> mesh, - const bool withGravity = true, - const double gravity = 10.0) : InternalForceModel() - { - auto tetMesh = std::dynamic_pointer_cast<vega::TetMesh>(mesh); - vega::StVKElementABCD* precomputedIntegrals = vega::StVKElementABCDLoader::load(tetMesh.get()); - m_stVKInternalForces = std::make_shared<vega::StVKInternalForces>(tetMesh.get(), precomputedIntegrals, withGravity, gravity); - m_vegaStVKStiffnessMatrix = std::make_shared<vega::StVKStiffnessMatrix>(m_stVKInternalForces.get()); - } + const bool withGravity = true, const double gravity = 10.0); /// /// \brief Destructor /// - virtual ~StVKForceModel() = default; + virtual ~StVKForceModel() override = default; /// /// \brief Get the internal force @@ -103,7 +92,6 @@ public: } protected: - std::shared_ptr<vega::StVKInternalForces> m_stVKInternalForces; std::shared_ptr<vega::SparseMatrix> m_vegaTangentStiffnessMatrix; std::shared_ptr<vega::StVKStiffnessMatrix> m_vegaStVKStiffnessMatrix; diff --git a/Source/DynamicalModels/ObjectModels/imstkAbstractDynamicalModel.h b/Source/DynamicalModels/ObjectModels/imstkAbstractDynamicalModel.h index e4573a692aa4401690ac39d7448799941c3657cf..945fdf0a0162c75a6882cedaa2ed291757f6ba2a 100644 --- a/Source/DynamicalModels/ObjectModels/imstkAbstractDynamicalModel.h +++ b/Source/DynamicalModels/ObjectModels/imstkAbstractDynamicalModel.h @@ -21,12 +21,9 @@ #pragma once -#include "imstkVectorizedState.h" #include "imstkGeometry.h" #include <set> -#include <string> -#include <unordered_map> namespace imstk { @@ -56,7 +53,7 @@ enum class TimeSteppingType }; /// -/// \class DynamicalModel +/// \class AbstractDynamicalModel /// /// \brief Abstract class for mathematical model of the physics governing the dynamic object /// @@ -102,6 +99,7 @@ public: /// /// \brief Update states + /// \todo: Fem specific, needs to be moved /// virtual void updateBodyStates(const Vectord& q, const StateUpdateType updateType = StateUpdateType::Displacement) = 0; diff --git a/Source/DynamicalModels/ObjectModels/imstkDynamicalModel.h b/Source/DynamicalModels/ObjectModels/imstkDynamicalModel.h index b1b79d3556403de0ca74a1e604586454ebea3100..36a7b9d9445fb42de4ccd75f8d432440f28f5a56 100644 --- a/Source/DynamicalModels/ObjectModels/imstkDynamicalModel.h +++ b/Source/DynamicalModels/ObjectModels/imstkDynamicalModel.h @@ -47,17 +47,17 @@ public: /// /// \brief Return the initial state of the problem /// - std::shared_ptr<StateType> getInitialState() { return m_initialState; } + std::shared_ptr<StateType> getInitialState() const { return m_initialState; } /// /// \brief Return the current state of the problem /// - std::shared_ptr<StateType> getCurrentState() { return m_currentState; } + std::shared_ptr<StateType> getCurrentState() const { return m_currentState; } /// /// \brief Return the previous state of the problem /// - std::shared_ptr<StateType> getPreviousState() { return m_previousState; } + std::shared_ptr<StateType> getPreviousState() const { return m_previousState; } /// /// \brief Reset the current state to the initial state diff --git a/Source/DynamicalModels/ObjectModels/imstkFEMDeformableBodyModel.cpp b/Source/DynamicalModels/ObjectModels/imstkFEMDeformableBodyModel.cpp index 00c523e8bac8825ffcfe97c79632a2cdbe3bb178..86394d79785932610b28358cc486a9e31e2388a3 100644 --- a/Source/DynamicalModels/ObjectModels/imstkFEMDeformableBodyModel.cpp +++ b/Source/DynamicalModels/ObjectModels/imstkFEMDeformableBodyModel.cpp @@ -19,32 +19,30 @@ =========================================================================*/ -// std lib -#include <fstream> - -//imstk #include "imstkFEMDeformableBodyModel.h" #include "imstkConjugateGradient.h" #include "imstkCorotationalFEMForceModel.h" -#include "imstkInternalForceModel.h" #include "imstkIsotropicHyperelasticFEMForceModel.h" #include "imstkLinearFEMForceModel.h" -#include "imstkMath.h" -#include "imstkSolverBase.h" +#include "imstkLogger.h" +#include "imstkNewtonSolver.h" #include "imstkStVKForceModel.h" #include "imstkTaskGraph.h" #include "imstkTimeIntegrator.h" #include "imstkVegaMeshIO.h" #include "imstkVolumetricMesh.h" +#include "imstkTypes.h" -// vega -#include "generateMassMatrix.h" -#include "generateMeshGraph.h" - +#include <generateMassMatrix.h> +#include <generateMeshGraph.h> +#ifdef WIN32 #pragma warning( push ) #pragma warning( disable : 4458 ) -#include "configFile.h" +#endif +#include <configFile.h> +#ifdef WIN32 #pragma warning( pop ) +#endif namespace imstk { @@ -521,7 +519,7 @@ FEMDeformableBodyModel::computeSemiImplicitSystemRHS(kinematicState& state } void -FEMDeformableBodyModel::computeImplicitSystemLHS(const kinematicState& stateAtT, +FEMDeformableBodyModel::computeImplicitSystemLHS(const kinematicState& imstkNotUsed(stateAtT), kinematicState& newState, const StateUpdateType updateType) { @@ -530,9 +528,6 @@ FEMDeformableBodyModel::computeImplicitSystemLHS(const kinematicState& stateAtT, switch (updateType) { case StateUpdateType::DeltaVelocity: - - stateAtT;// supress warning (state is not used in this update type hence can be ignored) - this->updateMassMatrix(); m_internalForceModel->getTangentStiffnessMatrix(newState.getQ(), m_K); this->updateDampingMatrix(); @@ -686,8 +681,10 @@ FEMDeformableBodyModel::updateBodyIntermediateStates( NonLinearSystem<SparseMatrixd>::VectorFunctionType FEMDeformableBodyModel::getFunction() { +#ifdef WIN32 #pragma warning( push ) #pragma warning( disable : 4100 ) +#endif // Function to evaluate the nonlinear objective function given the current state return [&, this](const Vectord& q, const bool semiImplicit)->const Vectord& @@ -701,15 +698,18 @@ FEMDeformableBodyModel::getFunction() } return m_Feff; }; - +#ifdef WIN32 #pragma warning( pop ) +#endif } NonLinearSystem<SparseMatrixd>::MatrixFunctionType FEMDeformableBodyModel::getFunctionGradient() { +#ifdef WIN32 #pragma warning( push ) #pragma warning( disable : 4100 ) +#endif // Gradient of the nonlinear objective function given the current state return [&, this](const Vectord& q)->const SparseMatrixd& { @@ -721,8 +721,9 @@ FEMDeformableBodyModel::getFunctionGradient() } return m_Keff; }; - +#ifdef WIN32 #pragma warning( pop ) +#endif } NonLinearSystem<SparseMatrixd>::UpdateFunctionType diff --git a/Source/DynamicalModels/ObjectModels/imstkFEMDeformableBodyModel.h b/Source/DynamicalModels/ObjectModels/imstkFEMDeformableBodyModel.h index 97d0f58d9ddd234aed821f806921b2519edcae0b..08ccffb0b9f30fb96ba2e32dfa76900fe3885b7f 100644 --- a/Source/DynamicalModels/ObjectModels/imstkFEMDeformableBodyModel.h +++ b/Source/DynamicalModels/ObjectModels/imstkFEMDeformableBodyModel.h @@ -21,14 +21,12 @@ #pragma once -// imstk #include "imstkDynamicalModel.h" #include "imstkInternalForceModelTypes.h" +#include "imstkVectorizedState.h" #include "imstkNonLinearSystem.h" -#include "imstkNewtonSolver.h" -// vega -#include "sparseMatrix.h" +#include <sparseMatrix.h> namespace vega { @@ -84,7 +82,7 @@ public: /// /// \brief Destructor /// - ~FEMDeformableBodyModel(); + ~FEMDeformableBodyModel() override; public: /// diff --git a/Source/DynamicalModels/ObjectModels/imstkLevelSetModel.cpp b/Source/DynamicalModels/ObjectModels/imstkLevelSetModel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ce797b1b384de37bec7b2ed2994d8ae085e7f33b --- /dev/null +++ b/Source/DynamicalModels/ObjectModels/imstkLevelSetModel.cpp @@ -0,0 +1,275 @@ +/*========================================================================= + + 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 "imstkLevelSetModel.h" +#include "imstkTaskGraph.h" +#include "imstkGeometryUtilities.h" +#include "imstkLogger.h" +#include "imstkSignedDistanceField.h" +#include "imstkParallelFor.h" +#include "imstkImplicitGeometry.h" +#include "imstkDataArray.h" +#include "imstkImageData.h" + +namespace imstk +{ +LevelSetModel::LevelSetModel() +{ + // If given an image data + m_validGeometryTypes = { + Geometry::Type::ImageData, + Geometry::Type::SignedDistanceField + }; + + // By default the level set defines a function for evolving the distances, this can be removed in subclasses + m_evolveQuantitiesNodes.push_back(std::make_shared<TaskNode>(std::bind(&LevelSetModel::evolveDistanceField, this), "Evolve Distances")); + m_taskGraph->addNode(m_evolveQuantitiesNodes.back()); + /// are all quantities evolved the same but with different force functions? +} + +bool +LevelSetModel::initialize() +{ + if (m_geometry == nullptr) + { + LOG(WARNING) << "Levelset missing geometry"; + return false; + } + + if (m_geometry->getType() == Geometry::Type::ImageData) + { + if (std::dynamic_pointer_cast<ImageData>(m_geometry)->getScalarType() != IMSTK_DOUBLE) + { + LOG(WARNING) << "Levelset only works with double image types"; + return false; + } + + m_mesh = std::make_shared<SignedDistanceField>(std::dynamic_pointer_cast<ImageData>(m_geometry)); + } + else + { + m_mesh = std::dynamic_pointer_cast<ImplicitGeometry>(m_geometry); + } + forwardGrad.setFunction(m_mesh); + backwardGrad.setFunction(m_mesh); + + // If dense update, we need a gradient image, which will store forward and backward gradient magnitudes + if (m_mesh->getType() == Geometry::Type::SignedDistanceField && !m_config->m_sparseUpdate) + { + auto sdfImage = std::dynamic_pointer_cast<SignedDistanceField>(m_mesh)->getImage(); + gradientMagnitudes = std::make_shared<ImageData>(); + gradientMagnitudes->allocate(IMSTK_DOUBLE, 2, sdfImage->getDimensions(), sdfImage->getSpacing(), sdfImage->getOrigin()); + } + + forwardGrad.setDx(Vec3i(1, 1, 1), std::dynamic_pointer_cast<SignedDistanceField>(m_mesh)->getImage()->getSpacing()); + backwardGrad.setDx(Vec3i(1, 1, 1), std::dynamic_pointer_cast<SignedDistanceField>(m_mesh)->getImage()->getSpacing()); + /*forwardGrad.setDx(std::dynamic_pointer_cast<SignedDistanceField>(m_mesh)->getImage()->getSpacing()); + backwardGrad.setDx(std::dynamic_pointer_cast<SignedDistanceField>(m_mesh)->getImage()->getSpacing());*/ + + return true; +} + +void +LevelSetModel::configure(std::shared_ptr<LevelSetModelConfig> config) +{ + LOG_IF(FATAL, (!this->getModelGeometry())) << "PbdModel::configure - Set PBD Model geometry before configuration!"; + + m_config = config; +} + +void +LevelSetModel::evolveDistanceField() +{ + auto sdf = std::dynamic_pointer_cast<SignedDistanceField>(m_mesh); + auto imageData = std::dynamic_pointer_cast<ImageData>(sdf->getImage()); + double* imgPtr = static_cast<double*>(imageData->getVoidPointer()); + const Vec3i& dim = imageData->getDimensions(); + //const Vec3d& spacing = imageData->getSpacing(); + //const Vec3d& origin = imageData->getOrigin(); + const double dt = m_config->m_dt; + + if (m_config->m_sparseUpdate) + { + // Sparse update + if (nodesToUpdate.size() == 0) + { + return; + } + + std::vector<std::tuple<size_t, Vec3i, double, Vec2d>> nodeUpdates; + nodeUpdates.reserve(nodesToUpdate.size()); + + // Compute gradients + for (std::unordered_map<size_t, std::tuple<Vec3i, double>>::iterator iter = nodesToUpdate.begin(); iter != nodesToUpdate.end(); iter++) + { + const size_t index = iter->first; + const Vec3i& coords = std::get<0>(iter->second); + const double f = std::get<1>(iter->second); + + // Gradients + const Vec3d gradPos = forwardGrad(Vec3d(coords[0], coords[1], coords[2])); + const Vec3d gradNeg = backwardGrad(Vec3d(coords[0], coords[1], coords[2])); + + const double posMag = + std::pow(std::max(gradNeg[0], 0.0), 2) + std::pow(std::min(gradPos[0], 0.0), 2) + + std::pow(std::max(gradNeg[1], 0.0), 2) + std::pow(std::min(gradPos[1], 0.0), 2) + + std::pow(std::max(gradNeg[2], 0.0), 2) + std::pow(std::min(gradPos[2], 0.0), 2); + + const double negMag = + std::pow(std::min(gradNeg[0], 0.0), 2) + std::pow(std::max(gradPos[0], 0.0), 2) + + std::pow(std::min(gradNeg[1], 0.0), 2) + std::pow(std::max(gradPos[1], 0.0), 2) + + std::pow(std::min(gradNeg[2], 0.0), 2) + std::pow(std::max(gradPos[2], 0.0), 2); + + nodeUpdates.push_back(std::tuple<size_t, Vec3i, double, Vec2d>(index, coords, f, Vec2d(negMag, posMag))); + } + + // Update levelset + const double constantVel = m_config->m_constantVelocity; + for (size_t i = 0; i < nodeUpdates.size(); i++) + { + const size_t index = std::get<0>(nodeUpdates[i]); + //const Vec3i& coords = std::get<1>(nodeUpdates[i]); + const double vel = std::get<2>(nodeUpdates[i]) + constantVel; + const Vec2d& g = std::get<3>(nodeUpdates[i]); + + // If speed function positive use forward difference (posMag) + if (vel > 0.0) + { + imgPtr[index] += dt * vel * std::sqrt(g[0]); + } + // If speed function negative use backward difference (negMag) + else if (vel < 0.0) + { + imgPtr[index] += dt * vel * std::sqrt(g[1]); + } + } + if (nodesToUpdate.size() > 0) + { + imageData->modified(); + nodesToUpdate.clear(); + } + } + else + { + // Dense update + double* gradientMagPtr = static_cast<double*>(gradientMagnitudes->getScalars()->getVoidPointer()); + + // Compute gradients + ParallelUtils::parallelFor(dim[2], + [&](const int& z) + { + int i = z * dim[0] * dim[1]; + for (int y = 0; y < dim[1]; y++) + { + for (int x = 0; x < dim[0]; x++, i++) + { + // Center of voxel + //const Vec3d pos = Vec3d(x, y, z).cwiseProduct(spacing) + shift; + + // Gradients + const Vec3d gradPos = forwardGrad(Vec3d(x, y, z)); + const Vec3d gradNeg = backwardGrad(Vec3d(x, y, z)); + + // neg + gradientMagPtr[i * 2] = + std::pow(std::min(gradNeg[0], 0.0), 2) + std::pow(std::max(gradPos[0], 0.0), 2) + + std::pow(std::min(gradNeg[1], 0.0), 2) + std::pow(std::max(gradPos[1], 0.0), 2) + + std::pow(std::min(gradNeg[2], 0.0), 2) + std::pow(std::max(gradPos[2], 0.0), 2); + + // pos + gradientMagPtr[i * 2 + 1] = + std::pow(std::max(gradNeg[0], 0.0), 2) + std::pow(std::min(gradPos[0], 0.0), 2) + + std::pow(std::max(gradNeg[1], 0.0), 2) + std::pow(std::min(gradPos[1], 0.0), 2) + + std::pow(std::max(gradNeg[2], 0.0), 2) + std::pow(std::min(gradPos[2], 0.0), 2); + } + } + }); + + // Uniform advance + const double constantVel = m_config->m_constantVelocity; + ParallelUtils::parallelFor(dim[0] * dim[1] * dim[2], + [&](const int& i) + { + // If speed function positive use forward difference + if (constantVel > 0.0) + { + imgPtr[i] += dt * constantVel * std::sqrt(gradientMagPtr[i * 2]); + } + // If speed function negative use backward difference + else if (constantVel < 0.0) + { + imgPtr[i] += dt * constantVel * std::sqrt(gradientMagPtr[i * 2 + 1]); + } + }); + imageData->modified(); + } +} + +void +LevelSetModel::addImpulse(const Vec3i& coord, double f) +{ + auto sdf = std::dynamic_pointer_cast<SignedDistanceField>(m_mesh); + auto imageData = std::dynamic_pointer_cast<ImageData>(sdf->getImage()); + const Vec3i& dim = imageData->getDimensions(); + + if (coord[0] >= 0 && coord[0] < dim[0] + && coord[1] >= 0 && coord[1] < dim[1] + && coord[2] >= 0 && coord[2] < dim[2]) + { + const size_t index = coord[0] + coord[1] * dim[0] + coord[2] * dim[0] * dim[1]; + if (nodesToUpdate.count(index) > 0) + { + nodesToUpdate[index] = std::tuple<Vec3i, double>(coord, std::get<1>(nodesToUpdate[index]) + f); + } + else + { + nodesToUpdate[index] = std::tuple<Vec3i, double>(coord, f); + } + } +} + +void +LevelSetModel::setImpulse(const Vec3i& coord, double f) +{ + auto sdf = std::dynamic_pointer_cast<SignedDistanceField>(m_mesh); + auto imageData = std::dynamic_pointer_cast<ImageData>(sdf->getImage()); + const Vec3i& dim = imageData->getDimensions(); + + if (coord[0] >= 0 && coord[0] < dim[0] + && coord[1] >= 0 && coord[1] < dim[1] + && coord[2] >= 0 && coord[2] < dim[2]) + { + const size_t index = coord[0] + coord[1] * dim[0] + coord[2] * dim[0] * dim[1]; + nodesToUpdate[index] = std::tuple<Vec3i, double>(coord, f); + } +} + +void +LevelSetModel::initGraphEdges(std::shared_ptr<TaskNode> source, std::shared_ptr<TaskNode> sink) +{ + // Given no fields are interacting all quantities should be able to update in parallel + for (size_t i = 0; i < m_evolveQuantitiesNodes.size(); i++) + { + m_taskGraph->addEdge(source, m_evolveQuantitiesNodes[i]); + m_taskGraph->addEdge(m_evolveQuantitiesNodes[i], sink); + } +} +} \ No newline at end of file diff --git a/Source/DynamicalModels/ObjectModels/imstkLevelSetModel.h b/Source/DynamicalModels/ObjectModels/imstkLevelSetModel.h new file mode 100644 index 0000000000000000000000000000000000000000..1b82b53e428c91924497caf123a538c3b17d0ad6 --- /dev/null +++ b/Source/DynamicalModels/ObjectModels/imstkLevelSetModel.h @@ -0,0 +1,120 @@ +/*========================================================================= + + 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 "imstkDynamicalModel.h" +#include "imstkLevelSetState.h" +#include "imstkImplicitFunctionFiniteDifferenceFunctor.h" + +#include <unordered_map> +#include <tuple> + +namespace imstk +{ +class ImageData; + +struct LevelSetModelConfig +{ + double m_dt = 0.001; ///> Time step size + bool m_sparseUpdate = false; ///> Only updates nodes that recieve force + bool m_useCurvature = false; + double m_k = 0.2; // Curvature term + double m_constantVelocity = 0.0; // Constant velocity +}; + +/// +/// \class LevelSetModel +/// +/// \brief This class implements a generic level set model, it requires both a forward +/// and backward finite differencing method +/// +class LevelSetModel : public DynamicalModel<LevelSetState> +{ +public: + /// + /// \brief Constructor + /// + LevelSetModel(); + + /// + /// \brief Destructor + /// + virtual ~LevelSetModel() override = default; + +public: + /// + /// \brief Set the time step size + /// + virtual void setTimeStep(const Real timeStep) override { m_config->m_dt = timeStep; } + + /// + /// \brief Returns the time step size + /// + virtual double getTimeStep() const override { return m_config->m_dt; } + + /// + /// \brief Update body states given the newest update and the type of update + /// + virtual void updateBodyStates(const Vectord& /*q*/, const StateUpdateType /*updateType = stateUpdateType::displacement*/) override {} + + /// + /// \brief Initialize the LevelSet model + /// + bool initialize() override; + + /// + /// \brief Configure the model + /// + void configure(std::shared_ptr<LevelSetModelConfig> config); + + virtual void evolveDistanceField(); + + void addImpulse(const Vec3i& coord, double f); + void setImpulse(const Vec3i& coord, double f); + + std::shared_ptr<TaskNode> getQuantityEvolveNode(size_t i) const { return m_evolveQuantitiesNodes[i]; } + +protected: + /// + /// \brief Setup the task graph of the LSM + /// + void initGraphEdges(std::shared_ptr<TaskNode> source, std::shared_ptr<TaskNode> sink) override; + +protected: + std::shared_ptr<ImplicitGeometry> m_mesh = nullptr; ///> Geometry on which the levelset evolves with + + std::vector<std::shared_ptr<TaskNode>> m_evolveQuantitiesNodes; + + std::shared_ptr<LevelSetModelConfig> m_config; + + std::unordered_map<size_t, std::tuple<Vec3i, double>> nodesToUpdate; + + std::shared_ptr<ImageData> gradientMagnitudes = nullptr; ///> Gradient magnitude field when using dense + + // I'm unable to use the more generic double/floating pt based version + // suspect floating point error + StructuredForwardGradient forwardGrad; + StructuredBackwardGradient backwardGrad; + /*ImplicitFunctionForwardGradient forwardGrad; + ImplicitFunctionBackwardGradient backwardGrad;*/ +}; +} \ No newline at end of file diff --git a/Source/DynamicalModels/ObjectModels/imstkPbdModel.cpp b/Source/DynamicalModels/ObjectModels/imstkPbdModel.cpp index a5a583654b712f1d1df16e669756a55adaa4e6d8..e95368d560fe689b565016ae2c1a86631c27a3c9 100644 --- a/Source/DynamicalModels/ObjectModels/imstkPbdModel.cpp +++ b/Source/DynamicalModels/ObjectModels/imstkPbdModel.cpp @@ -20,9 +20,10 @@ =========================================================================*/ #include "imstkPbdModel.h" -#include "imstkGeometryUtilities.h" #include "imstkGraph.h" #include "imstkLineMesh.h" +#include "imstkLogger.h" +#include "imstkParallelUtils.h" #include "imstkPbdAreaConstraint.h" #include "imstkPbdBendConstraint.h" #include "imstkPbdConstantDensityConstraint.h" @@ -35,15 +36,13 @@ #include "imstkTaskGraph.h" #include "imstkTetrahedralMesh.h" -#include <unordered_map> - namespace imstk { PbdModel::PbdModel() : DynamicalModel(DynamicalModelType::PositionBasedDynamics), - m_constraints(std::make_shared<PBDConstraintVector>()), - m_partitionedConstraints(std::make_shared<std::vector<PBDConstraintVector>>()), m_mass(std::make_shared<StdVectorOfReal>()), m_invMass(std::make_shared<StdVectorOfReal>()), + m_constraints(std::make_shared<PBDConstraintVector>()), + m_partitionedConstraints(std::make_shared<std::vector<PBDConstraintVector>>()), m_parameters(std::make_shared<PBDModelConfig>()) { m_validGeometryTypes = { @@ -77,6 +76,19 @@ PBDModelConfig::enableFEMConstraint(PbdConstraint::Type type, PbdFEMConstraint:: m_FEMConstraints.push_back({ type, material }); } +void +PBDModelConfig::setSolverType(const PbdConstraint::SolverType& type) +{ + if (type == PbdConstraint::SolverType::GCD) + { + LOG(WARNING) << "GCD is NOT implemented yet, use xPBD instead"; + m_solverType = PbdConstraint::SolverType::xPBD; + return; + } + + m_solverType = type; +} + void PbdModel::configure(std::shared_ptr<PBDModelConfig> params) { @@ -398,7 +410,6 @@ PbdModel::initializeBendConstraints(const double stiffness) // Create constraints const auto& lineMesh = std::static_pointer_cast<LineMesh>(m_mesh); const auto& elements = lineMesh->getLinesVertices(); - const auto nV = lineMesh->getNumVertices(); // Iterate sets of two segments for (size_t k = 0; k < elements.size() - 1; k++) diff --git a/Source/DynamicalModels/ObjectModels/imstkPbdModel.h b/Source/DynamicalModels/ObjectModels/imstkPbdModel.h index 691ad576ccbb71b76fd6e08cfdfaf8a8c7c5c5af..641797c75ed9dcb577a1acda8f5a3a78caaf068e 100644 --- a/Source/DynamicalModels/ObjectModels/imstkPbdModel.h +++ b/Source/DynamicalModels/ObjectModels/imstkPbdModel.h @@ -25,7 +25,6 @@ #include "imstkPbdCollisionConstraint.h" #include "imstkPbdFEMConstraint.h" #include "imstkPbdState.h" -#include "imstkLogger.h" namespace imstk { @@ -82,17 +81,7 @@ struct PBDModelConfig /// /// \brief Set the PBD solver type /// - void setSolverType(const PbdConstraint::SolverType& type) - { - if (type == PbdConstraint::SolverType::GCD) - { - LOG(WARNING) << "GCD is NOT implemented yet, use xPBD instead"; - m_solverType = PbdConstraint::SolverType::xPBD; - return; - } - - m_solverType = type; - } + void setSolverType(const PbdConstraint::SolverType& type); PbdConstraint::SolverType m_solverType = PbdConstraint::SolverType::xPBD; }; diff --git a/Source/DynamicalModels/ObjectModels/imstkReducedStVKBodyModel.h b/Source/DynamicalModels/ObjectModels/imstkReducedStVKBodyModel.h index b8f55955b2676b86608c8d7bf861c99eedc82a9a..f11f092adf49d9e2b2069928c931b53b67cc7707 100644 --- a/Source/DynamicalModels/ObjectModels/imstkReducedStVKBodyModel.h +++ b/Source/DynamicalModels/ObjectModels/imstkReducedStVKBodyModel.h @@ -24,6 +24,7 @@ #include <memory> #include "imstkDynamicalModel.h" +#include "imstkVectorizedState.h" #include "imstkNonLinearSystem.h" #include "imstkLogger.h" @@ -366,4 +367,4 @@ protected: private: std::shared_ptr<TaskNode> m_solveNode = nullptr; }; -} // namespace imstk \ No newline at end of file +} // namespace imstk diff --git a/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel.cpp b/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel.cpp index 937c3da0647e8b440f3859e6aceeaec84d3a05f8..fe614262f424ed16543cb44430792911f3e1832f 100644 --- a/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel.cpp +++ b/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel.cpp @@ -18,14 +18,13 @@ limitations under the License. =========================================================================*/ + #include "imstkRigidBodyModel.h" -#include "imstkSurfaceMesh.h" #include "imstkCube.h" -#include "imstkSphere.h" +#include "imstkLogger.h" #include "imstkPlane.h" -#include "physx/extensions/PxSimpleFactory.h" - -#include <g3log/g3log.hpp> +#include "imstkSphere.h" +#include "imstkSurfaceMesh.h" namespace imstk { @@ -272,7 +271,7 @@ RigidBodyModel::createMesh() } } -//TODO: Have to implement update physics geometry +// \todo: Have to implement update physics geometry void RigidBodyModel::updatePhysicsGeometry() { @@ -300,7 +299,7 @@ RigidBodyModel::updatePhysicsGeometry() m_force = Vec3d(0., 0., 0.); } -//TODO: Have to implement update physics spring geometry +// \todo: Have to implement update physics spring geometry void RigidBodyModel::addForce(const Vec3d& force, const Vec3d& pos, bool wakeup) { @@ -312,16 +311,20 @@ RigidBodyModel::addForce(const Vec3d& force, const Vec3d& pos, bool wakeup) PxForceMode::eFORCE, wakeup); } +#ifdef WIN32 #pragma warning( push ) #pragma warning( disable : 4100 ) -//TODO updating body states as in +#endif +// \todo: updating body states as in void RigidBodyModel::updateBodyStates(const Vectord& q, const StateUpdateType updateType /* = stateUpdateType::displacement*/) { LOG(WARNING) << "RigidBodyModel::updateBodyStates Not implemented!"; } +#ifdef WIN32 #pragma warning( pop ) +#endif void RigidBodyModel::configure(const std::shared_ptr<RigidBodyConfig> matProperty) diff --git a/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel.h b/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel.h index 89a90ee285d6e7c003d07992c8954ce009e621bd..150d68af45029f25df6ed0db2963859d5f75c50e 100644 --- a/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel.h +++ b/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel.h @@ -67,7 +67,7 @@ public: Geometry::Type::SurfaceMesh }; }; - ~RigidBodyModel() = default; + virtual ~RigidBodyModel() override = default; /// /// \brief Initialize the physx dynamic model @@ -77,7 +77,7 @@ public: /// /// \brief Configure the model /// - // TODO: Setting of mass and gravity has to happen somewhere. + // \todo: Setting of mass and gravity has to happen somewhere. void configure(const std::shared_ptr<RigidBodyConfig> matProperty); /// diff --git a/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel2.cpp b/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6af881aaef48cd6a84a41d172f46e4e0c42d8f4f --- /dev/null +++ b/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel2.cpp @@ -0,0 +1,387 @@ +/*========================================================================= + + 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 "imstkRigidBodyModel2.h" +#include "imstkParallelFor.h" +#include "imstkProjectedGaussSeidelSolver.h" +#include "imstkRbdConstraint.h" +#include "imstkTaskGraph.h" + +namespace imstk +{ +namespace expiremental +{ +RigidBodyModel2::RigidBodyModel2() : + m_config(std::make_shared<RigidBodyModel2Config>()), + m_pgsSolver(std::make_shared<ProjectedGaussSeidelSolver<double>>()) +{ + m_computeTentativeVelocities = std::make_shared<TaskNode>( + std::bind(&RigidBodyModel2::computeTentativeVelocities, this), "RigidBodyModel_ComputeTentativeVelocities"); + m_solveNode = std::make_shared<TaskNode>(std::bind(&RigidBodyModel2::solveConstraints, this), "RigidBodyModel_Solve"); + m_integrateNode = std::make_shared<TaskNode>(std::bind(&RigidBodyModel2::integrate, this), "RigidBodyModel_Integrate"); + + m_taskGraph->addNode(m_computeTentativeVelocities); + m_taskGraph->addNode(m_solveNode); + m_taskGraph->addNode(m_integrateNode); +} + +std::shared_ptr<RigidBody> +RigidBodyModel2::addRigidBody() +{ + m_bodies.push_back(std::make_shared<RigidBody>()); + m_modified = true; + return m_bodies.back(); +} + +void +RigidBodyModel2::removeRigidBody(std::shared_ptr<RigidBody> rbd) +{ + std::vector<std::shared_ptr<RigidBody>>::iterator bodyIter = std::find(m_bodies.begin(), m_bodies.end(), rbd); + if (bodyIter != m_bodies.end()) + { + m_bodies.erase(bodyIter); + } + m_modified = true; +} + +bool +RigidBodyModel2::initialize() +{ + // Only run initialize if a body has been added/removed + if (!m_modified) + { + return true; + } + + // Compute the initial state + std::shared_ptr<RigidBodyState2> state = std::make_shared<RigidBodyState2>(); + state->resize(m_bodies.size()); + std::vector<bool>& isStatic = state->getIsStatic(); + StdVectorOfReal& invMasses = state->getInvMasses(); + StdVectorOfMat3d& invInteriaTensors = state->getInvIntertiaTensors(); + StdVectorOfVec3d& positions = state->getPositions(); + StdVectorOfQuatd& orientations = state->getOrientations(); + StdVectorOfVec3d& velocities = state->getVelocities(); + StdVectorOfVec3d& angularVelocities = state->getAngularVelocities(); + StdVectorOfVec3d& tentativeVelocities = state->getTentatveVelocities(); + StdVectorOfVec3d& tentativeAngularVelocities = state->getTentativeAngularVelocities(); + StdVectorOfVec3d& forces = state->getForces(); + StdVectorOfVec3d& torques = state->getTorques(); + + m_Minv = Eigen::SparseMatrix<double>(m_bodies.size() * 6, m_bodies.size() * 6); + std::vector<Eigen::Triplet<double>> mInvTriplets; + mInvTriplets.reserve((9 + 3) * m_bodies.size()); + for (size_t i = 0; i < m_bodies.size(); i++) + { + RigidBody& body = *m_bodies[i]; + + // Set the intial state + isStatic[i] = body.m_isStatic; + invMasses[i] = (body.m_mass == 0.0) ? 0.0 : 1.0 / body.m_mass; + invInteriaTensors[i] = body.m_intertiaTensor.inverse(); // Is there any easy way to check invertible + positions[i] = body.m_initPos; + orientations[i] = body.m_initOrientation; + velocities[i] = body.m_initVelocity; + angularVelocities[i] = body.m_initAngularVelocity; + tentativeVelocities[i] = body.m_initVelocity; + tentativeAngularVelocities[i] = body.m_initAngularVelocity; + forces[i] = body.m_initForce; + torques[i] = body.m_initTorque; + + // Link it up with the state + body.m_pos = &positions[i]; + body.m_orientation = &orientations[i]; + body.m_velocity = &velocities[i]; + body.m_angularVelocity = &angularVelocities[i]; + body.m_force = &forces[i]; + body.m_torque = &torques[i]; + m_locations[m_bodies[i].get()] = static_cast<StorageIndex>(i); + + if (!body.m_isStatic) + { + // invMass expanded to 3x3 matrix + const double invMass = invMasses[i]; + const Mat3d& invInvertia = invInteriaTensors[i]; + int index = static_cast<int>(i * 6); + mInvTriplets.push_back(Eigen::Triplet<double>(index, index, invMass)); + index++; + mInvTriplets.push_back(Eigen::Triplet<double>(index, index, invMass)); + index++; + mInvTriplets.push_back(Eigen::Triplet<double>(index, index, invMass)); + index++; + for (unsigned int c = 0; c < 3; c++) + { + for (unsigned int r = 0; r < 3; r++) + { + mInvTriplets.push_back(Eigen::Triplet<double>(index + r, index + c, invInvertia(c, r))); + } + } + } + } + m_Minv.setFromTriplets(mInvTriplets.begin(), mInvTriplets.end()); + + // Copy to initial state + m_initialState = std::make_shared<RigidBodyState2>(*state); + m_currentState = state; + m_previousState = std::make_shared<RigidBodyState2>(*state); + m_modified = false; + + return true; +} + +void +RigidBodyModel2::configure(std::shared_ptr<RigidBodyModel2Config> config) +{ + m_config = config; +} + +void +RigidBodyModel2::computeTentativeVelocities() +{ + const double dt = m_config->m_dt; + const StdVectorOfReal& invMasses = getCurrentState()->getInvMasses(); + const StdVectorOfMat3d& invInteriaTensors = getCurrentState()->getInvIntertiaTensors(); + StdVectorOfVec3d& tentativeVelocities = getCurrentState()->getTentatveVelocities(); + StdVectorOfVec3d& tentativeAngularVelocities = getCurrentState()->getTentativeAngularVelocities(); + StdVectorOfVec3d& forces = getCurrentState()->getForces(); + StdVectorOfVec3d& torques = getCurrentState()->getTorques(); + const Vec3d& fG = m_config->m_gravity; + + // Sum gravity to the forces + ParallelUtils::parallelFor(forces.size(), [&forces, &fG](const size_t& i) + { + forces[i] += fG; + }); + + // Compute the desired velocites, later we will solve for the proper velocities, + // adjusted for the constraints + ParallelUtils::parallelFor(tentativeVelocities.size(), [&](const size_t& i) + { + tentativeVelocities[i] += forces[i] * invMasses[i] * dt; + tentativeAngularVelocities[i] += invInteriaTensors[i] * torques[i] * dt; + }); +} + +void +RigidBodyModel2::solveConstraints() +{ + // Solves the current constraints of the system, then discards them + if (m_constraints.size() == 0) + { + return; + } + + std::shared_ptr<RigidBodyState2> state = getCurrentState(); + const std::vector<bool>& isStatic = state->getIsStatic(); + const StdVectorOfVec3d& tentativeVelocities = state->getTentatveVelocities(); + const StdVectorOfVec3d& tentativeAngularVelocities = state->getTentativeAngularVelocities(); + StdVectorOfVec3d& forces = state->getForces(); + StdVectorOfVec3d& torques = state->getTorques(); + + Eigen::VectorXd F; + Eigen::VectorXd V = Eigen::VectorXd(state->size() * 6); + Eigen::VectorXd Fext = Eigen::VectorXd(state->size() * 6); + + // Fill the forces and tenative velocities vectors + StorageIndex j = 0; + for (size_t i = 0; i < state->size(); i++) + { + if (!isStatic[i]) + { + const Vec3d& velocity = tentativeVelocities[i]; + const Vec3d& angularVelocity = tentativeAngularVelocities[i]; + const Vec3d& force = forces[i]; + const Vec3d& torque = torques[i]; + Fext(j) = force[0]; + V(j) = velocity[0]; + j++; + Fext(j) = force[1]; + V(j) = velocity[1]; + j++; + Fext(j) = force[2]; + V(j) = velocity[2]; + j++; + Fext(j) = torque[0]; + V(j) = angularVelocity[0]; + j++; + Fext(j) = torque[1]; + V(j) = angularVelocity[1]; + j++; + Fext(j) = torque[2]; + V(j) = angularVelocity[2]; + j++; + } + else + { + for (StorageIndex k = 0; k < 6; k++) + { + Fext(j + k) = 0.0; + V(j + k) = 0.0; + } + j += 6; + } + } + + // Now construct the sparse jacobian matrix for every constraint (object vs constraint) + Eigen::SparseMatrix<double> J(m_constraints.size(), state->size() * 6); + Eigen::VectorXd Vu(m_constraints.size()); // Push Factor + Eigen::MatrixXd cu(m_constraints.size(), 2); // Mins and maxes + std::vector<Eigen::Triplet<double>> JTriplets; + JTriplets.reserve(m_constraints.size() * 12); + j = 0; + for (std::list<std::shared_ptr<RbdConstraint>>::iterator iter = m_constraints.begin(); iter != m_constraints.end(); iter++) + { + std::shared_ptr<RbdConstraint> constraint = *iter; + Vu(j) = constraint->vu; + + // Object 1 + StorageIndex k = 0; + if (constraint->m_obj1 != nullptr) + { + const StorageIndex obj1Location = m_locations[constraint->m_obj1.get()]; + const StorageIndex start1 = obj1Location * 6; + for (StorageIndex c = 0; c < 2; c++) + { + for (StorageIndex r = 0; r < 3; r++) + { + JTriplets.push_back(Eigen::Triplet<double>(j, start1 + k, constraint->J(r, c))); + k++; + } + } + } + + // Object 2 + if (constraint->m_obj2 != nullptr) + { + const StorageIndex obj2Location = m_locations[constraint->m_obj2.get()]; + const StorageIndex start2 = obj2Location * 6; + k = 0; + for (StorageIndex c = 2; c < 4; c++) + { + for (StorageIndex r = 0; r < 3; r++) + { + JTriplets.push_back(Eigen::Triplet<double>(j, start2 + k, constraint->J(r, c))); + k++; + } + } + } + + cu(j, 0) = constraint->range[0]; + cu(j, 1) = constraint->range[1]; + j++; + } + J.setFromTriplets(JTriplets.begin(), JTriplets.end()); + + const double dt = m_config->m_dt; + Eigen::SparseMatrix<double> A = J * m_Minv * J.transpose(); + Eigen::VectorXd b = Vu / dt - J * (V / dt + m_Minv * Fext); + + /* std::cout << "Minv: " << std::endl << m_Minv.toDense() << std::endl; + std::cout << "J: " << std::endl << J.toDense() << std::endl; + std::cout << "A: " << std::endl << A.toDense() << std::endl; + std::cout << std::endl; + std::cout << "Vu: " << std::endl << Vu << std::endl; + std::cout << "V: " << std::endl << V << std::endl; + std::cout << "b: " << std::endl << b << std::endl;*/ + + m_pgsSolver->setA(&A); + //pgsSolver.setGuess(F); // Not using warm starting + m_pgsSolver->setMaxIterations(m_config->m_maxNumIterations); + F = J.transpose() * m_pgsSolver->solve(b, cu); + + // Apply back + j = 0; + for (size_t i = 0; i < state->size(); i++, j += 6) + { + forces[i] += Vec3d(F(j), F(j + 1), F(j + 2)); + torques[i] += Vec3d(F(j + 3), F(j + 4), F(j + 5)); + } + + //std::cout << std::endl << "Forces/Torques: " << F << std::endl; + + m_constraints.clear(); +} + +void +RigidBodyModel2::integrate() +{ + // Just a basic symplectic euler + const double dt = m_config->m_dt; + const double velocityDamping = m_config->m_velocityDamping; + const double angularVelocityDamping = m_config->m_angularVelocityDamping; + + const std::vector<bool>& isStatic = getCurrentState()->getIsStatic(); + + const StdVectorOfReal& invMasses = getCurrentState()->getInvMasses(); + const StdVectorOfMat3d& invInteriaTensors = getCurrentState()->getInvIntertiaTensors(); + + StdVectorOfVec3d& positions = getCurrentState()->getPositions(); + StdVectorOfQuatd& orientations = getCurrentState()->getOrientations(); + + StdVectorOfVec3d& velocities = getCurrentState()->getVelocities(); + StdVectorOfVec3d& angularVelocities = getCurrentState()->getAngularVelocities(); + + StdVectorOfVec3d& tentativeVelocities = getCurrentState()->getTentatveVelocities(); + StdVectorOfVec3d& tentativeAngularVelocities = getCurrentState()->getTentativeAngularVelocities(); + + StdVectorOfVec3d& forces = getCurrentState()->getForces(); + StdVectorOfVec3d& torques = getCurrentState()->getTorques(); + + ParallelUtils::parallelFor(positions.size(), [&](const size_t& i) + { + if (!isStatic[i]) + { + velocities[i] += forces[i] * invMasses[i] * dt; + velocities[i] *= velocityDamping; + angularVelocities[i] += invInteriaTensors[i] * torques[i] * dt; + angularVelocities[i] *= angularVelocityDamping; + positions[i] += velocities[i] * dt; + { + const Quatd q = Quatd(0.0, + angularVelocities[i][0], + angularVelocities[i][1], + angularVelocities[i][2]) * orientations[i]; + orientations[i].x() += q.x() * dt; + orientations[i].y() += q.y() * dt; + orientations[i].z() += q.z() * dt; + orientations[i].w() += q.w() * dt; + orientations[i].normalize(); + } + } + + // Reset + forces[i] = Vec3d(0.0, 0.0, 0.0); + torques[i] = Vec3d(0.0, 0.0, 0.0); + tentativeVelocities[i] = velocities[i]; + tentativeAngularVelocities[i] = angularVelocities[i]; + }); +} + +void +RigidBodyModel2::initGraphEdges(std::shared_ptr<TaskNode> source, std::shared_ptr<TaskNode> sink) +{ + m_taskGraph->addEdge(source, m_computeTentativeVelocities); + m_taskGraph->addEdge(m_computeTentativeVelocities, m_solveNode); + m_taskGraph->addEdge(m_solveNode, m_integrateNode); + m_taskGraph->addEdge(m_integrateNode, sink); +} +} +} \ No newline at end of file diff --git a/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel2.h b/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel2.h new file mode 100644 index 0000000000000000000000000000000000000000..debed6f82a9d1800d588f3af5b2c6bd0cfe70f41 --- /dev/null +++ b/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel2.h @@ -0,0 +1,156 @@ +/*========================================================================= + + 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 "imstkDynamicalModel.h" +#include "imstkRigidBodyState2.h" + +#include <list> +#include <unordered_map> + +namespace imstk +{ +template<typename ScalarType> +class ProjectedGaussSeidelSolver; + +namespace expiremental +{ +class RbdConstraint; +struct RigidBody; + +struct RigidBodyModel2Config +{ + double m_dt = 0.001; ///> Time step size + Vec3d m_gravity = Vec3d(0.0, -9.8, 0.0); + unsigned int m_maxNumIterations = 10; + double m_velocityDamping = 0.99; + double m_angularVelocityDamping = 0.99; +}; + +/// +/// \class RigidBodyModel2 +/// +/// \brief This class implements a constraint based rigid body linear system +/// with pgs solver +/// +class RigidBodyModel2 : public DynamicalModel<RigidBodyState2> +{ +public: + using StorageIndex = Eigen::SparseMatrix<double>::StorageIndex; + +public: + /// + /// \brief Constructor + /// + RigidBodyModel2(); + + /// + /// \brief Destructor + /// + virtual ~RigidBodyModel2() override = default; + +public: + /// + /// \brief Set the time step size + /// + virtual void setTimeStep(const Real timeStep) override { m_config->m_dt = timeStep; } + + /// + /// \brief Returns the time step size + /// + virtual double getTimeStep() const override { return m_config->m_dt; } + + std::shared_ptr<RigidBodyModel2Config> getConfig() const { return m_config; } + + /// + /// \brief Adds a body to the system, must call initialize for changes to effect + /// returns its reference + /// + std::shared_ptr<RigidBody> addRigidBody(); + + /// + /// \brief Adds a constraint to be solved + /// + void addConstraint(std::shared_ptr<RbdConstraint> constraint) { m_constraints.push_back(constraint); } + + /// + /// \brief Removes a body from the system, must call initialize for changes to effect + /// + void removeRigidBody(std::shared_ptr<RigidBody> body); + + /// + /// \todo: remove + /// + virtual void updateBodyStates(const Vectord& /*q*/, const StateUpdateType /*updateType = stateUpdateType::displacement*/) override {} + + /// + /// \brief Initialize the RigidBody model + /// + bool initialize() override; + + /// + /// \brief Configure the model + /// + void configure(std::shared_ptr<RigidBodyModel2Config> config); + + /// + /// \brief Computes the velocities + /// + void computeTentativeVelocities(); + + /// + /// \brief Solve the current constraints of the model, then discards + /// + void solveConstraints(); + + /// + /// \brief Integrate the model state + /// + void integrate(); + + std::shared_ptr<TaskNode> getComputeTentativeVelocitiesNode() const { return m_computeTentativeVelocities; } + std::shared_ptr<TaskNode> getSolveNode() const { return m_solveNode; } + std::shared_ptr<TaskNode> getIntegrateNode() const { return m_integrateNode; } + +protected: + /// + /// \brief Setup the task graph of the LSM + /// + void initGraphEdges(std::shared_ptr<TaskNode> source, std::shared_ptr<TaskNode> sink) override; + +protected: + std::shared_ptr<RigidBodyModel2Config> m_config; + + std::shared_ptr<TaskNode> m_computeTentativeVelocities; + std::shared_ptr<TaskNode> m_solveNode; + std::shared_ptr<TaskNode> m_integrateNode; + +protected: + std::shared_ptr<ProjectedGaussSeidelSolver<double>> m_pgsSolver; + Eigen::SparseMatrix<double> m_Minv; + std::list<std::shared_ptr<RbdConstraint>> m_constraints; + std::vector<std::shared_ptr<RigidBody>> m_bodies; + std::unordered_map<RigidBody*, StorageIndex> m_locations; + bool m_modified = true; +}; +} +} \ No newline at end of file diff --git a/Source/DynamicalModels/ObjectModels/imstkRigidBodyWorld.cpp b/Source/DynamicalModels/ObjectModels/imstkRigidBodyWorld.cpp index f886a8c61ca3382ebe78543e98fa0d70e9fcebcd..d6289fa4a50367bbcff730ee689816c85e950574 100644 --- a/Source/DynamicalModels/ObjectModels/imstkRigidBodyWorld.cpp +++ b/Source/DynamicalModels/ObjectModels/imstkRigidBodyWorld.cpp @@ -18,9 +18,9 @@ limitations under the License. =========================================================================*/ -#include "imstkRigidBodyWorld.h" -#include <g3log/g3log.hpp> +#include "imstkRigidBodyWorld.h" +#include "imstkLogger.h" #define MAX_CONTACTS_PER_BODY 16 @@ -34,7 +34,7 @@ RigidBodyWorld::RigidBodyWorld() m_Physics = PxCreatePhysics(PX_PHYSICS_VERSION, *m_Foundation, PxTolerancesScale(), true, m_Pvd); m_Cooking = PxCreateCooking(PX_PHYSICS_VERSION, *m_Foundation, PxCookingParams(PxTolerancesScale())); - // TODO: move this into a separate structure that user can supply + // \todo: move this into a separate structure that user can supply PxSceneDesc sceneDesc(m_Physics->getTolerancesScale()); sceneDesc.gravity = PxVec3(0.0f, -9.81f, 0.0f); m_Dispatcher = PxDefaultCpuDispatcherCreate(2); diff --git a/Source/DynamicalModels/ObjectModels/imstkRigidBodyWorld.h b/Source/DynamicalModels/ObjectModels/imstkRigidBodyWorld.h index f822c55ce3604a4e30f015d47df73a052b7b2224..2a1b9bb6ef36e17b1514e034edbbb3b0a43eab80 100644 --- a/Source/DynamicalModels/ObjectModels/imstkRigidBodyWorld.h +++ b/Source/DynamicalModels/ObjectModels/imstkRigidBodyWorld.h @@ -19,12 +19,14 @@ =========================================================================*/ -#ifndef imstkRigidBodyWorld_h -#define imstkRigidBodyWorld_h +#pragma once + +#include "imstkDynamicalModel.h" +#include "imstkRigidBodyState.h" #define PhysX_RELEASE(x) if (x) { x->release(); x = NULL; } -#include "physx/PxConfig.h" +#include <physx/PxConfig.h> #if !defined(NDEBUG) && !defined(_DEBUG) // PhysX tests for _DEBUG preprocessor definition in a debug build // On Windows, MSVC defines this automatically @@ -32,20 +34,11 @@ # define _DEBUG 1 # define imstkPxPhysXAPI_DEBUG #endif -#include "physx/PxPhysicsAPI.h" +#include <physx/PxPhysicsAPI.h> #ifdef imstkPxPhysXAPI_DEBUG #undef _DEBUG #undef imstkPxPhysXAPI_DEBUG #endif -#include "physx/extensions/PxDefaultErrorCallback.h" - -#include "imstkDynamicalModel.h" -#include "imstkRigidBodyState.h" -#include "imstkSurfaceMesh.h" - -//#include "../snippets/snippetcommon/SnippetPrint.h" -//#include "../snippets/snippetcommon/SnippetPVD.h" -//#include "../snippets/snippetutils/SnippetUtils.h" namespace imstk { @@ -105,5 +98,3 @@ private: RigidBodyWorld(); }; } // imstk - -#endif // imstkRigidBodyWorld_h diff --git a/Source/DynamicalModels/ObjectModels/imstkSPHKernels.h b/Source/DynamicalModels/ObjectModels/imstkSPHKernels.h index 0fcde0a84740196a07b7fde4e9acf799e712cd65..352b4f32431e5d2f70b4bda6331124bfd67c6906 100644 --- a/Source/DynamicalModels/ObjectModels/imstkSPHKernels.h +++ b/Source/DynamicalModels/ObjectModels/imstkSPHKernels.h @@ -21,11 +21,8 @@ #pragma once -#include <cmath> -#include <cassert> - #include "imstkMath.h" -#include <g3log/g3log.hpp> +#include "imstkLogger.h" namespace imstk { @@ -54,10 +51,14 @@ public: m_radius = radius; m_radius2 = m_radius * m_radius; +#ifdef WIN32 #pragma warning(push) #pragma warning(disable:4127) +#endif if (N == 2) +#ifdef WIN32 #pragma warning(pop) +#endif { m_k = Real(4.0) / (PI * std::pow(m_radius, 8)); m_l = -Real(24.0) / (PI * std::pow(m_radius, 8)); @@ -163,10 +164,14 @@ public: m_radius = radius; m_radius2 = m_radius * m_radius; +#ifdef WIN32 #pragma warning(push) #pragma warning(disable:4127) +#endif if (N == 2) +#ifdef WIN32 #pragma warning(pop) +#endif { const auto radius5 = std::pow(m_radius, 5); m_k = Real(10.0) / (PI * radius5); @@ -252,10 +257,14 @@ public: m_radius = radius; m_radius2 = m_radius * m_radius; +#ifdef WIN32 #pragma warning(push) #pragma warning(disable:4127) +#endif CHECK(N != 2) << "Unimplemented function"; +#ifdef WIN32 #pragma warning(pop) +#endif m_k = Real(32.0) / (PI * std::pow(m_radius, 9)); m_c = std::pow(m_radius, 6) / Real(64.0); diff --git a/Source/DynamicalModels/ObjectModels/imstkSPHModel.cpp b/Source/DynamicalModels/ObjectModels/imstkSPHModel.cpp index 890c114aed0abfd0b61a3f6ba273146ca34a9f3b..95f4ae6f9bafc41eb2bae8b06f2f9c6705a3ea48 100644 --- a/Source/DynamicalModels/ObjectModels/imstkSPHModel.cpp +++ b/Source/DynamicalModels/ObjectModels/imstkSPHModel.cpp @@ -20,7 +20,6 @@ limitations under the License. =========================================================================*/ #include "imstkSPHModel.h" -#include "imstkLogger.h" #include "imstkParallelUtils.h" #include "imstkPointSet.h" #include "imstkTaskGraph.h" @@ -130,6 +129,11 @@ SPHModel::SPHModel() : DynamicalModel<SPHKinematicState>(DynamicalModelType::Smo { moveParticles(getTimeStep()); }); + //m_computePositionNode = + // m_taskGraph->addFunction("SPHModel_ComputePositions", [&]() + // { + // moveParticles(getTimeStep()); + // }); } bool @@ -207,6 +211,7 @@ SPHModel::initGraphEdges(std::shared_ptr<TaskNode> source, std::shared_ptr<TaskN m_taskGraph->addEdge(m_integrateNode, m_updateVelocityNode); m_taskGraph->addEdge(m_updateVelocityNode, m_moveParticlesNode); m_taskGraph->addEdge(m_moveParticlesNode, sink); + } void diff --git a/Source/DynamicalModels/ObjectModels/imstkSPHModel.h b/Source/DynamicalModels/ObjectModels/imstkSPHModel.h index 7ca4d3ca2c8159af3858b32ef37401acb8c164c6..9982b805c02cf5d0588367c603052986a3db44cf 100644 --- a/Source/DynamicalModels/ObjectModels/imstkSPHModel.h +++ b/Source/DynamicalModels/ObjectModels/imstkSPHModel.h @@ -31,7 +31,6 @@ namespace imstk { -class ComputeNode; class PointSet; /// @@ -302,7 +301,6 @@ protected: std::shared_ptr<TaskNode> m_updateVelocityNode = nullptr; std::shared_ptr<TaskNode> m_computeViscosityNode = nullptr; std::shared_ptr<TaskNode> m_moveParticlesNode = nullptr; - std::shared_ptr<TaskNode> m_normalizeDensityNode = nullptr; std::shared_ptr<TaskNode> m_collectNeighborDensityNode = nullptr; diff --git a/Source/Rendering/imstkRenderer.cpp b/Source/DynamicalModels/ObjectStates/imstkLevelSetState.cpp similarity index 80% rename from Source/Rendering/imstkRenderer.cpp rename to Source/DynamicalModels/ObjectStates/imstkLevelSetState.cpp index 92afd991bd943ef0352de759c5342ffe3fe0d3a9..1ef13b6f12d8d02c303615e4262d1b49fc173818 100644 --- a/Source/Rendering/imstkRenderer.cpp +++ b/Source/DynamicalModels/ObjectStates/imstkLevelSetState.cpp @@ -19,20 +19,17 @@ =========================================================================*/ -#include "imstkRenderer.h" +#include "imstkLevelSetState.h" namespace imstk { void -Renderer::setMode(const Renderer::Mode mode, const bool enableVR) +LevelSetState::initialize(std::shared_ptr<ImplicitGeometry> geometry) { - m_VrEnabled = enableVR; - m_currentMode = mode; } -const Renderer::Mode& -Renderer::getMode() +void +LevelSetState::setState(std::shared_ptr<LevelSetState> rhs) { - return m_currentMode; } } \ No newline at end of file diff --git a/Source/DynamicalModels/ObjectStates/imstkLevelSetState.h b/Source/DynamicalModels/ObjectStates/imstkLevelSetState.h new file mode 100644 index 0000000000000000000000000000000000000000..bbdd016141a4e521a16863759a7ef16f517d48d4 --- /dev/null +++ b/Source/DynamicalModels/ObjectStates/imstkLevelSetState.h @@ -0,0 +1,58 @@ +/*========================================================================= + + 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 "imstkImplicitGeometry.h" + +namespace imstk +{ +class ImplicitGeometry; + +/// +/// \class LevelSetState +/// +/// \brief Generic definition of the state of the levelset via ImplicitGeometry +/// The state gives a set of implicit geometries, each of which represent the state +/// of a quantity on the levelset. Each implicit geometry then gives the signed function value +/// and gradient of the quantity. Usually this would be distances, but one may also evolve densities +/// or even heat on any domain +/// +class LevelSetState : public ImplicitGeometry +{ +public: + /// + /// \brief Default constructor/destructor + /// + LevelSetState() = default; + virtual ~LevelSetState() override = default; + + /// + /// \brief Initialize the pbd state + /// + void initialize(std::shared_ptr<ImplicitGeometry> geometry); + + /// + /// \brief Set the state to a given one + /// + void setState(std::shared_ptr<LevelSetState> rhs); +}; +} // imstk diff --git a/Source/DynamicalModels/ObjectStates/imstkPbdState.cpp b/Source/DynamicalModels/ObjectStates/imstkPbdState.cpp index 13c84c079c919daf9bc67d76a1d167534e89e937..f411988badc3cc601158d8f1189d18c49571fb66 100644 --- a/Source/DynamicalModels/ObjectStates/imstkPbdState.cpp +++ b/Source/DynamicalModels/ObjectStates/imstkPbdState.cpp @@ -20,7 +20,6 @@ =========================================================================*/ #include "imstkPbdState.h" -#include "imstkPointSet.h" namespace imstk { diff --git a/Source/DynamicalModels/ObjectStates/imstkRigidBodyState.h b/Source/DynamicalModels/ObjectStates/imstkRigidBodyState.h index b67ce30c98cce95d020b5a7b7080949d4f3efad8..d2ac882dd9a08345ee2c58635fb92ba3769b82dc 100644 --- a/Source/DynamicalModels/ObjectStates/imstkRigidBodyState.h +++ b/Source/DynamicalModels/ObjectStates/imstkRigidBodyState.h @@ -21,10 +21,6 @@ #pragma once -#include <Eigen/Dense> -#include <memory> -#include <vector> - #include "imstkMath.h" namespace imstk diff --git a/Source/DynamicalModels/ObjectStates/imstkRigidBodyState2.h b/Source/DynamicalModels/ObjectStates/imstkRigidBodyState2.h new file mode 100644 index 0000000000000000000000000000000000000000..327f1610b06c84f615cf427abffa1a6738543468 --- /dev/null +++ b/Source/DynamicalModels/ObjectStates/imstkRigidBodyState2.h @@ -0,0 +1,116 @@ +/*========================================================================= + + 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 "imstkMath.h" + +namespace imstk +{ +/// +/// \class RigidBodyState2 +/// +/// \brief Kinematic state of rigid bodies within a system +/// +class RigidBodyState2 +{ +public: + void resize(const size_t size) + { + m_invMasses.resize(size); + m_invIntertiaTensors.resize(size); + m_positions.resize(size); + m_orientations.resize(size); + m_velocities.resize(size); + m_angularVelocities.resize(size); + m_tentativeVelocities.resize(size); + m_tentativeAngularVelocities.resize(size); + m_forces.resize(size); + m_torques.resize(size); + m_isStatic.resize(size); + } + + size_t size() const { return m_invMasses.size(); } + + const std::vector<bool>& getIsStatic() const { return m_isStatic; } + std::vector<bool>& getIsStatic() { return m_isStatic; } + + const StdVectorOfReal& getInvMasses() const { return m_invMasses; } + StdVectorOfReal& getInvMasses() { return m_invMasses; } + const StdVectorOfMat3d& getInvIntertiaTensors() const { return m_invIntertiaTensors; } + StdVectorOfMat3d& getInvIntertiaTensors() { return m_invIntertiaTensors; } + + const StdVectorOfVec3d& getPositions() const { return m_positions; } + StdVectorOfVec3d& getPositions() { return m_positions; } + const StdVectorOfQuatd& getOrientations() const { return m_orientations; } + StdVectorOfQuatd& getOrientations() { return m_orientations; } + + const StdVectorOfVec3d& getVelocities() const { return m_velocities; } + StdVectorOfVec3d& getVelocities() { return m_velocities; } + const StdVectorOfVec3d& getAngularVelocities() const { return m_angularVelocities; } + StdVectorOfVec3d& getAngularVelocities() { return m_angularVelocities; } + + const StdVectorOfVec3d& getTentatveVelocities() const { return m_tentativeVelocities; } + StdVectorOfVec3d& getTentatveVelocities() { return m_tentativeVelocities; } + const StdVectorOfVec3d& getTentativeAngularVelocities() const { return m_tentativeAngularVelocities; } + StdVectorOfVec3d& getTentativeAngularVelocities() { return m_tentativeAngularVelocities; } + + const StdVectorOfVec3d& getForces() const { return m_forces; } + StdVectorOfVec3d& getForces() { return m_forces; } + const StdVectorOfVec3d& getTorques() const { return m_torques; } + StdVectorOfVec3d& getTorques() { return m_torques; } + + /// + /// \brief Set the state to a given one, copies + /// + void setState(std::shared_ptr<RigidBodyState2> state) + { + m_invMasses = state->getInvMasses(); + m_invIntertiaTensors = state->getInvIntertiaTensors(); + + m_positions = state->getPositions(); + m_orientations = state->getOrientations(); + + m_velocities = state->getVelocities(); + m_angularVelocities = state->getAngularVelocities(); + + m_forces = state->getForces(); + m_torques = state->getTorques(); + } + +private: + StdVectorOfReal m_invMasses; + StdVectorOfMat3d m_invIntertiaTensors; + + StdVectorOfVec3d m_positions; + StdVectorOfQuatd m_orientations; + + StdVectorOfVec3d m_velocities; + StdVectorOfVec3d m_angularVelocities; + StdVectorOfVec3d m_tentativeVelocities; ///> Tentative velocities for mid update + StdVectorOfVec3d m_tentativeAngularVelocities; + + StdVectorOfVec3d m_forces; + StdVectorOfVec3d m_torques; + + std::vector<bool> m_isStatic; +}; +} // imstk \ No newline at end of file diff --git a/Source/DynamicalModels/TimeIntegrators/imstkNewmarkBeta.h b/Source/DynamicalModels/TimeIntegrators/imstkNewmarkBeta.h index 596d01ef4bfcf8374633f79e77219e63ddb1f036..3733fcde5cedc3db6f3fdea52f6541da09a7f7d8 100644 --- a/Source/DynamicalModels/TimeIntegrators/imstkNewmarkBeta.h +++ b/Source/DynamicalModels/TimeIntegrators/imstkNewmarkBeta.h @@ -22,7 +22,6 @@ #pragma once #include "imstkTimeIntegrator.h" -#include "imstkLogger.h" namespace imstk { diff --git a/Source/Filtering/CMakeLists.txt b/Source/Filtering/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..adffa7aa0c2a7edc280b7812ac1b98353dab960c --- /dev/null +++ b/Source/Filtering/CMakeLists.txt @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Create target +#----------------------------------------------------------------------------- +file(GLOB hFiles *.h) +file(GLOB cppFiles *cpp) + +include(imstkAddLibrary) +imstk_add_library( Filtering + H_FILES + ${hFiles} + CPP_FILES + ${cppFiles} + DEPENDS + Geometry + DataStructures + ${VTK_LIBRARIES}) diff --git a/Source/Filtering/imstkAppendMesh.cpp b/Source/Filtering/imstkAppendMesh.cpp new file mode 100644 index 0000000000000000000000000000000000000000..18b0109bc065e3888b18161272dbfdcaed696aac --- /dev/null +++ b/Source/Filtering/imstkAppendMesh.cpp @@ -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. + +=========================================================================*/ + +#include "imstkAppendMesh.h" +#include "imstkGeometryUtilities.h" +#include "imstkLogger.h" +#include "imstkSurfaceMesh.h" + +#include <vtkAppendPolyData.h> + +namespace imstk +{ +AppendMesh::AppendMesh() +{ + setNumberOfInputPorts(1); + setNumberOfOutputPorts(1); + setOutput(std::make_shared<SurfaceMesh>()); +} + +void +AppendMesh::addInputMesh(std::shared_ptr<SurfaceMesh> inputMesh) +{ + setNumberOfInputPorts(getNumberOfInputPorts() + 1); + setInput(inputMesh, getNumberOfInputPorts() - 1); +} + +std::shared_ptr<SurfaceMesh> +AppendMesh::getOutputMesh() const +{ + return std::static_pointer_cast<SurfaceMesh>(getOutput(0)); +} + +void +AppendMesh::requestUpdate() +{ + vtkNew<vtkAppendPolyData> filter; + for (int i = 0; i < getNumberOfInputPorts(); i++) + { + std::shared_ptr<SurfaceMesh> inputMesh = std::dynamic_pointer_cast<SurfaceMesh>(getInput(0)); + if (inputMesh == nullptr) + { + LOG(WARNING) << "Input " << i << " invalid"; + return; + } + filter->AddInputData(GeometryUtils::copyToVtkPolyData(inputMesh)); + } + filter->Update(); + + setOutput(GeometryUtils::copyToSurfaceMesh(filter->GetOutput())); +} +} \ No newline at end of file diff --git a/Source/Filtering/imstkAppendMesh.h b/Source/Filtering/imstkAppendMesh.h new file mode 100644 index 0000000000000000000000000000000000000000..16c940a30b3f650bc72e4cfcfb37b548ee6fadbd --- /dev/null +++ b/Source/Filtering/imstkAppendMesh.h @@ -0,0 +1,47 @@ +/*========================================================================= + + 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 "imstkGeometryAlgorithm.h" + +namespace imstk +{ +class SurfaceMesh; + +/// +/// \class CleanMesh +/// +/// \brief This filter appends two SurfaceMeshes, no topological connections are made +/// +class AppendMesh : public GeometryAlgorithm +{ +public: + AppendMesh(); + virtual ~AppendMesh() override = default; + +public: + void addInputMesh(std::shared_ptr<SurfaceMesh> inputMesh); + std::shared_ptr<SurfaceMesh> getOutputMesh() const; + +protected: + void requestUpdate() override; +}; +} \ No newline at end of file diff --git a/Source/Filtering/imstkCleanMesh.cpp b/Source/Filtering/imstkCleanMesh.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a0629b1723d8a8edf5dc4151cd98f6a738d2ddde --- /dev/null +++ b/Source/Filtering/imstkCleanMesh.cpp @@ -0,0 +1,91 @@ +/*========================================================================= + + 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 "imstkCleanMesh.h" +#include "imstkLineMesh.h" +#include "imstkSurfaceMesh.h" +#include "imstkLogger.h" +#include "imstkGeometryUtilities.h" + +#include <vtkCleanPolyData.h> + +namespace imstk +{ +CleanMesh::CleanMesh() +{ + setNumberOfInputPorts(1); + setNumberOfOutputPorts(1); + setOutput(std::make_shared<SurfaceMesh>()); +} + +std::shared_ptr<SurfaceMesh> +CleanMesh::getOutputMesh() const +{ + return std::dynamic_pointer_cast<SurfaceMesh>(getOutput(0)); +} + +void +CleanMesh::setInputMesh(std::shared_ptr<SurfaceMesh> inputMesh) +{ + setInput(inputMesh, 0); +} + +void +CleanMesh::requestUpdate() +{ + std::shared_ptr<PointSet> inputMesh = std::dynamic_pointer_cast<PointSet>(getInput(0)); + if (inputMesh == nullptr) + { + LOG(WARNING) << "No inputMesh to clean"; + return; + } + vtkSmartPointer<vtkPolyData> inputMeshVtk = nullptr; + if (inputMesh->getType() == Geometry::Type::LineMesh) + { + inputMeshVtk = GeometryUtils::copyToVtkPolyData(std::dynamic_pointer_cast<LineMesh>(inputMesh)); + } + else if (inputMesh->getType() == Geometry::Type::SurfaceMesh) + { + inputMeshVtk = GeometryUtils::copyToVtkPolyData(std::dynamic_pointer_cast<SurfaceMesh>(inputMesh)); + } + else + { + LOG(WARNING) << "Unsupported mesh type"; + return; + } + + vtkNew<vtkCleanPolyData> filter; + filter->SetInputData(inputMeshVtk); + filter->SetTolerance(m_Tolerance); + filter->SetAbsoluteTolerance(m_AbsoluteTolerance); + filter->SetToleranceIsAbsolute(m_UseAbsolute); + filter->Update(); + + if (inputMesh->getType() == Geometry::Type::LineMesh) + { + setOutput(GeometryUtils::copyToLineMesh(filter->GetOutput())); + } + else if (inputMesh->getType() == Geometry::Type::SurfaceMesh) + { + setOutput(GeometryUtils::copyToSurfaceMesh(filter->GetOutput())); + } +} +} \ No newline at end of file diff --git a/Source/Filtering/imstkCleanMesh.h b/Source/Filtering/imstkCleanMesh.h new file mode 100644 index 0000000000000000000000000000000000000000..d62ba3a12292d37b2e8d92852b02c1810c4fcf0c --- /dev/null +++ b/Source/Filtering/imstkCleanMesh.h @@ -0,0 +1,77 @@ +/*========================================================================= + + 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 "imstkGeometryAlgorithm.h" + +namespace imstk +{ +class SurfaceMesh; + +/// +/// \class CleanMesh +/// +/// \brief This filter can merge duplicate points and cells, it only works with +/// LineMesh and SurfaceMesh. It accepts a tolerance as a fraction of the length +/// of bounding box of the input data or an absolute tolerance +/// +class CleanMesh : public GeometryAlgorithm +{ +public: + CleanMesh(); + virtual ~CleanMesh() override = default; + +public: + std::shared_ptr<SurfaceMesh> getOutputMesh() const; + + /// + /// \brief Required input, port 0 + /// + void setInputMesh(std::shared_ptr<SurfaceMesh> inputMesh); + + imstkGetMacro(Tolerance, double); + imstkGetMacro(AbsoluteTolerance, double); + imstkGetMacro(UseAbsolute, bool); + + /// + /// \brief Set the tolerance for point merging, fraction of bounding box length + /// + void setTolerance(const double tolerance) + { + this->m_Tolerance = tolerance; + m_UseAbsolute = false; + } + + void setAbsoluteTolerance(const double tolerance) + { + this->m_AbsoluteTolerance = tolerance; + m_UseAbsolute = true; + } + +protected: + void requestUpdate() override; + +private: + double m_Tolerance = 0.0; + double m_AbsoluteTolerance = 1.0; + bool m_UseAbsolute = false; +}; +} \ No newline at end of file diff --git a/Source/Filtering/imstkExtractEdges.cpp b/Source/Filtering/imstkExtractEdges.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e710ca0013008d5bbb9d05ef1d4947e45fc0a9c4 --- /dev/null +++ b/Source/Filtering/imstkExtractEdges.cpp @@ -0,0 +1,72 @@ +/*========================================================================= + + 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 "imstkExtractEdges.h" +#include "imstkGeometryUtilities.h" +#include "imstkLineMesh.h" +#include "imstkLogger.h" +#include "imstkSurfaceMesh.h" + +#include <vtkExtractEdges.h> +#include <vtkTriangleFilter.h> + +namespace imstk +{ +ExtractEdges::ExtractEdges() +{ + setNumberOfInputPorts(1); + setNumberOfOutputPorts(1); + setOutput(std::make_shared<LineMesh>()); +} + +void +ExtractEdges::setInputMesh(std::shared_ptr<SurfaceMesh> inputMesh) +{ + setInput(inputMesh, 0); +} + +std::shared_ptr<LineMesh> +ExtractEdges::getOutputMesh() const +{ + return std::static_pointer_cast<LineMesh>(getOutput(0)); +} + +void +ExtractEdges::requestUpdate() +{ + std::shared_ptr<SurfaceMesh> inputMesh = std::dynamic_pointer_cast<SurfaceMesh>(getInput(0)); + if (inputMesh == nullptr) + { + LOG(WARNING) << "No inputMesh to extract edges from"; + return; + } + + vtkNew<vtkExtractEdges> extractEdges; + extractEdges->SetInputData(GeometryUtils::copyToVtkPolyData(inputMesh)); + extractEdges->Update(); + + vtkNew<vtkTriangleFilter> triangleFilter; + triangleFilter->SetInputData(extractEdges->GetOutput()); + triangleFilter->Update(); + + setOutput(GeometryUtils::copyToLineMesh(triangleFilter->GetOutput())); +} +} \ No newline at end of file diff --git a/Source/Filtering/imstkExtractEdges.h b/Source/Filtering/imstkExtractEdges.h new file mode 100644 index 0000000000000000000000000000000000000000..4867b95c0d19f07d1812777f214150b74ca4aa73 --- /dev/null +++ b/Source/Filtering/imstkExtractEdges.h @@ -0,0 +1,49 @@ +/*========================================================================= + + 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 "imstkGeometryAlgorithm.h" + +namespace imstk +{ +class LineMesh; +class SurfaceMesh; + +/// +/// \class ExtractEdges +/// +/// \brief This filter extracts the edges of a SurfaceMesh producing a LineMesh +/// +class ExtractEdges : public GeometryAlgorithm +{ +public: + ExtractEdges(); + virtual ~ExtractEdges() override = default; + +public: + std::shared_ptr<LineMesh> getOutputMesh() const; + + void setInputMesh(std::shared_ptr<SurfaceMesh> inputMesh); + +protected: + void requestUpdate() override; +}; +} \ No newline at end of file diff --git a/Source/Filtering/imstkGeometryAlgorithm.cpp b/Source/Filtering/imstkGeometryAlgorithm.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f556e8ab08a0f7da58ad352e931fa4b6fe50bd29 --- /dev/null +++ b/Source/Filtering/imstkGeometryAlgorithm.cpp @@ -0,0 +1,73 @@ +/*========================================================================= + + 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 "imstkGeometryAlgorithm.h" +#include "imstkLogger.h" + +namespace imstk +{ +void +GeometryAlgorithm::setInput(std::shared_ptr<Geometry> inputGeometry, size_t port) +{ + if (m_inputs.count(port) == 0) + { + LOG(WARNING) << "Tried to set input " << port << " on filter with " << m_NumberOfInputPorts << " ports"; + } + m_inputs[port] = inputGeometry; +} + +void +GeometryAlgorithm::setOutput(std::shared_ptr<Geometry> outputGeometry, size_t port) +{ + if (m_outputs.count(port) == 0) + { + LOG(WARNING) << "Tried to set output " << port << " on filter with " << m_NumberOfOutputPorts << " ports"; + } + m_outputs[port] = outputGeometry; +} + +void +GeometryAlgorithm::setNumberOfInputPorts(size_t numPorts) +{ + this->m_NumberOfInputPorts = numPorts; + // Add entries in the map for it + for (size_t i = 0; i < numPorts; i++) + { + if (m_inputs.count(i) == 0) + { + m_inputs[i] = nullptr; + } + } +} + +void +GeometryAlgorithm::setNumberOfOutputPorts(size_t numPorts) +{ + this->m_NumberOfOutputPorts = numPorts; + // Add entries in the map for it + for (size_t i = 0; i < numPorts; i++) + { + if (m_outputs.count(i) == 0) + { + m_outputs[i] = nullptr; + } + } +} +} \ No newline at end of file diff --git a/Source/Filtering/imstkGeometryAlgorithm.h b/Source/Filtering/imstkGeometryAlgorithm.h new file mode 100644 index 0000000000000000000000000000000000000000..2c7ba088b58ae7630316426a1581d4ecc4eba8c2 --- /dev/null +++ b/Source/Filtering/imstkGeometryAlgorithm.h @@ -0,0 +1,108 @@ +/*========================================================================= + + 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 <memory> +#include <unordered_map> + +#define imstkSetMacro(name, dataType) \ + virtual void set ## name(dataType _arg) \ + { \ + if (this->m_ ## name != _arg) \ + { \ + this->m_ ## name = _arg; \ + } \ + } +#define imstkGetMacro(name, dataType) \ + virtual dataType get ## name() { return this->m_ ## name; } + +namespace imstk +{ +class Geometry; + +// Base class for geometry algorithms +class GeometryAlgorithm +{ +protected: + GeometryAlgorithm() = default; + +public: + GeometryAlgorithm(const GeometryAlgorithm&) = delete; + GeometryAlgorithm(const GeometryAlgorithm&&) = delete; + virtual ~GeometryAlgorithm() = default; + +public: + /// + /// \brief Returns input geometry given port, returns nullptr if doesn't exist + /// + std::shared_ptr<Geometry> getInput(size_t port = 0) const { return (m_inputs.count(port) == 0) ? nullptr : m_inputs.at(port); } + /// + /// \brief Returns output geometry given port, returns nullptr if doesn't exist + /// + std::shared_ptr<Geometry> getOutput(size_t port = 0) const { return m_outputs.count(port) == 0 ? nullptr : m_outputs.at(port); } + + /// + /// \brief Set the input at the port + /// + void setInput(std::shared_ptr<Geometry> inputGeometry, size_t port = 0); + +protected: + /// + /// \brief Set the output at the port + /// + void setOutput(std::shared_ptr<Geometry> inputGeometry, size_t port = 0); + + imstkGetMacro(NumberOfInputPorts, size_t); + imstkGetMacro(NumberOfOutputPorts, size_t); + + /// + /// \brief Sets the amount of input ports + /// + void setNumberOfInputPorts(size_t numPorts); + + /// + /// \brief Sets the amount of output ports + /// + void setNumberOfOutputPorts(size_t numPorts); + +public: + //void modified() { this->m_modified = true; } + + void update() + { + //if (m_modified) + //{ + requestUpdate(); + //} + //m_modified = false; + } + +protected: + virtual void requestUpdate() = 0; + +private: + std::unordered_map<size_t, std::shared_ptr<Geometry>> m_inputs; + std::unordered_map<size_t, std::shared_ptr<Geometry>> m_outputs; + //bool m_modified = true; + size_t m_NumberOfInputPorts = 1; + size_t m_NumberOfOutputPorts = 1; +}; +} \ No newline at end of file diff --git a/Source/Filtering/imstkImageDistanceTransform.cpp b/Source/Filtering/imstkImageDistanceTransform.cpp new file mode 100644 index 0000000000000000000000000000000000000000..48aaeceab3a948707e14dcc5d3498d358260a950 --- /dev/null +++ b/Source/Filtering/imstkImageDistanceTransform.cpp @@ -0,0 +1,127 @@ +/*========================================================================= + + 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 "imstkImageDistanceTransform.h" +#include "imstkGeometryUtilities.h" +#include "imstkImageData.h" +#include "imstkLogger.h" + +#include <vtkImageCast.h> +#include <vtkImageData.h> +#include <vtkImageEuclideanDistance.h> +#include <vtkImageMathematics.h> +#include <vtkImageShiftScale.h> + +namespace imstk +{ +ImageDistanceTransform::ImageDistanceTransform() +{ + setNumberOfInputPorts(1); + setNumberOfOutputPorts(1); + setOutput(std::make_shared<ImageData>(), 0); +} + +std::shared_ptr<ImageData> +ImageDistanceTransform::getOutputImage() const +{ + return std::dynamic_pointer_cast<ImageData>(getOutput(0)); +} + +void +ImageDistanceTransform::setInputImage(std::shared_ptr<ImageData> refImage) +{ + setInput(refImage, 0); +} + +void +ImageDistanceTransform::requestUpdate() +{ + std::shared_ptr<ImageData> imageInput = std::dynamic_pointer_cast<ImageData>(getInput(0)); + + if (imageInput == nullptr) + { + LOG(WARNING) << "Missing input image data"; + return; + } + + vtkSmartPointer<vtkImageData> imageInputVtk = GeometryUtils::coupleVtkImageData(imageInput); + + // Compute the inner distance + vtkSmartPointer<vtkImageEuclideanDistance> innerDistanceFilter = vtkSmartPointer<vtkImageEuclideanDistance>::New(); + innerDistanceFilter->SetInputData(imageInputVtk); + innerDistanceFilter->ConsiderAnisotropyOn(); + innerDistanceFilter->SetAlgorithmToSaito(); + innerDistanceFilter->SetDimensionality(3); + innerDistanceFilter->Update(); + vtkSmartPointer<vtkImageCast> innerCastFilter = vtkSmartPointer<vtkImageCast>::New(); + innerCastFilter->SetInputData(innerDistanceFilter->GetOutput()); + innerCastFilter->SetOutputScalarTypeToFloat(); + innerCastFilter->Update(); + vtkSmartPointer<vtkImageMathematics> innerSqrtFilter = vtkSmartPointer<vtkImageMathematics>::New(); + innerSqrtFilter->SetInput1Data(innerCastFilter->GetOutput()); + innerSqrtFilter->SetOperationToSquareRoot(); + innerSqrtFilter->Update(); + + // Invert the input mask to compute the outer distance transform + double* range = imageInputVtk->GetScalarRange(); + vtkSmartPointer<vtkImageShiftScale> invertFilter = vtkSmartPointer<vtkImageShiftScale>::New(); + invertFilter->SetInputData(imageInputVtk); + invertFilter->SetShift(-range[1]); + invertFilter->SetScale(-1.0); + invertFilter->Update(); + + // Compute the outer distance + vtkSmartPointer<vtkImageEuclideanDistance> outerDistanceFilter = vtkSmartPointer<vtkImageEuclideanDistance>::New(); + outerDistanceFilter->SetInputData(invertFilter->GetOutput()); + outerDistanceFilter->ConsiderAnisotropyOn(); + outerDistanceFilter->SetAlgorithmToSaito(); + outerDistanceFilter->SetDimensionality(3); + outerDistanceFilter->Update(); + vtkSmartPointer<vtkImageCast> outerCastFilter = vtkSmartPointer<vtkImageCast>::New(); + outerCastFilter->SetInputData(outerDistanceFilter->GetOutput()); + outerCastFilter->SetOutputScalarTypeToFloat(); + outerCastFilter->Update(); + vtkSmartPointer<vtkImageMathematics> outerSqrtFilter = vtkSmartPointer<vtkImageMathematics>::New(); + outerSqrtFilter->SetInput1Data(outerCastFilter->GetOutput()); + outerSqrtFilter->SetOperationToSquareRoot(); + outerSqrtFilter->Update(); + + // Inner distance should be negative + vtkSmartPointer<vtkImageData> innerImage = innerSqrtFilter->GetOutput(); + if (!m_UseUnsigned) + { + vtkSmartPointer<vtkImageShiftScale> negFilter = vtkSmartPointer<vtkImageShiftScale>::New(); + negFilter->SetInputData(innerSqrtFilter->GetOutput()); + negFilter->SetScale(-1.0); + negFilter->Update(); + innerImage = negFilter->GetOutput(); + } + + // Finally combine the negative and positive + vtkSmartPointer<vtkImageMathematics> addImageFilter = vtkSmartPointer<vtkImageMathematics>::New(); + addImageFilter->SetInput1Data(outerSqrtFilter->GetOutput()); + addImageFilter->SetInput2Data(innerImage); + addImageFilter->SetOperationToAdd(); + addImageFilter->Update(); + + setOutput(GeometryUtils::copyToImageData(addImageFilter->GetOutput())); +} +} \ No newline at end of file diff --git a/Source/Filtering/imstkImageDistanceTransform.h b/Source/Filtering/imstkImageDistanceTransform.h new file mode 100644 index 0000000000000000000000000000000000000000..1064c96395a282e168d56559ecb0d00a050a6704 --- /dev/null +++ b/Source/Filtering/imstkImageDistanceTransform.h @@ -0,0 +1,57 @@ +/*========================================================================= + + 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 "imstkGeometryAlgorithm.h" + +namespace imstk +{ +class ImageData; + +/// +/// \class ImageDistanceTransform +/// +/// \brief This filter generates a signed or unsigned distance transform from a binary mask +/// +class ImageDistanceTransform : public GeometryAlgorithm +{ +public: + ImageDistanceTransform(); + virtual ~ImageDistanceTransform() override = default; + +public: + std::shared_ptr<ImageData> getOutputImage() const; + + /// + /// \brief Required input, port 0 + /// + void setInputImage(std::shared_ptr<ImageData> refImage); + + imstkGetMacro(UseUnsigned, bool); + imstkSetMacro(UseUnsigned, bool); + +protected: + void requestUpdate() override; + +private: + bool m_UseUnsigned = false; +}; +} \ No newline at end of file diff --git a/Source/Filtering/imstkImageGradient.cpp b/Source/Filtering/imstkImageGradient.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a9738f77fe22512c189364be79e63e55d8dc32e2 --- /dev/null +++ b/Source/Filtering/imstkImageGradient.cpp @@ -0,0 +1,77 @@ +/*========================================================================= + + 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 "imstkImageGradient.h" +#include "imstkGeometryUtilities.h" +#include "imstkImageData.h" +#include "imstkLogger.h" + +#include <vtkImageData.h> +#include <vtkImageGradient.h> +#include <vtkImageGradientMagnitude.h> + +namespace imstk +{ +ImageGradient::ImageGradient() +{ + setNumberOfInputPorts(1); + setNumberOfOutputPorts(1); + setOutput(std::make_shared<PointSet>()); +} + +void +ImageGradient::setInputImage(std::shared_ptr<ImageData> inputImage) +{ + setInput(inputImage, 0); +} + +void +ImageGradient::requestUpdate() +{ + std::shared_ptr<ImageData> inputImage = std::dynamic_pointer_cast<ImageData>(getInput(0)); + if (inputImage == nullptr) + { + LOG(WARNING) << "No input to compute gradients"; + return; + } + if (inputImage->getNumComponents() != 1) + { + LOG(WARNING) << "Can only compute gradient on single channel image"; + return; + } + vtkSmartPointer<vtkImageData> inputImageVtk = GeometryUtils::coupleVtkImageData(inputImage); + if (m_ComputeMagnitude) + { + vtkNew<vtkImageGradientMagnitude> gradientMagnitude; + gradientMagnitude->SetInputData(inputImageVtk); + gradientMagnitude->Update(); + setOutput(GeometryUtils::copyToImageData(gradientMagnitude->GetOutput())); + } + else + { + vtkNew<vtkImageGradient> gradients; + gradients->SetInputData(inputImageVtk); + gradients->SetHandleBoundaries(true); + gradients->Update(); + setOutput(GeometryUtils::copyToImageData(gradients->GetOutput())); + } +} +} \ No newline at end of file diff --git a/Source/Filtering/imstkImageGradient.h b/Source/Filtering/imstkImageGradient.h new file mode 100644 index 0000000000000000000000000000000000000000..61a44de2d4152f004ca19a4031d5a7b594bb571f --- /dev/null +++ b/Source/Filtering/imstkImageGradient.h @@ -0,0 +1,58 @@ +/*========================================================================= + + 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 "imstkGeometryAlgorithm.h" + +namespace imstk +{ +class ImageData; + +/// +/// \class ImageGradient +/// +/// \brief This filter computes the gradient or magnitude using sobels kernel over an image +/// +class ImageGradient : public GeometryAlgorithm +{ +public: + ImageGradient(); + virtual ~ImageGradient() override = default; + +public: + /// + /// \brief Required input, port 0 + /// + void setInputImage(std::shared_ptr<ImageData> inputImage); + + /// + /// \brief If on, a single channel magnitude image is output, if off, a 3 component gradient is produced + /// + imstkSetMacro(ComputeMagnitude, bool); + imstkGetMacro(ComputeMagnitude, bool); + +protected: + void requestUpdate() override; + +private: + bool m_ComputeMagnitude; +}; +} \ No newline at end of file diff --git a/Source/Filtering/imstkImageResample.cpp b/Source/Filtering/imstkImageResample.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1f6261c431574397f2cd3a5ba432f555a93841b1 --- /dev/null +++ b/Source/Filtering/imstkImageResample.cpp @@ -0,0 +1,71 @@ +/*========================================================================= + + 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 "imstkImageResample.h" +#include "imstkDataArray.h" +#include "imstkGeometryUtilities.h" +#include "imstkImageData.h" +#include "imstkLogger.h" +#include "imstkParallelFor.h" +#include <vtkImageData.h> +#include <vtkImageResample.h> +#include <vtkSmartPointer.h> + +namespace imstk +{ +ImageResample::ImageResample() +{ + setNumberOfInputPorts(1); + setNumberOfOutputPorts(1); + setOutput(std::make_shared<ImageData>()); +} + +std::shared_ptr<ImageData> +ImageResample::getOutputImage() const +{ + return std::dynamic_pointer_cast<ImageData>(getOutput(0)); +} + +void +ImageResample::setInputImage(std::shared_ptr<ImageData> inputData) +{ + setInput(inputData, 0); +} + +void +ImageResample::requestUpdate() +{ + std::shared_ptr<ImageData> inputImage = std::dynamic_pointer_cast<ImageData>(getInput(0)); + if (inputImage == nullptr) + { + LOG(WARNING) << "No inputImage to resample"; + return; + } + + vtkNew<vtkImageResample> resample; + resample->SetInputData(GeometryUtils::copyToVtkImageData(inputImage)); + resample->SetInterpolationModeToLinear(); + resample->SetOutputExtent(0, m_Dimensions[0] - 1, 0, m_Dimensions[1] - 1, 0, m_Dimensions[2] - 1); + resample->Update(); + + setOutput(GeometryUtils::copyToImageData(resample->GetOutput())); +} +} \ No newline at end of file diff --git a/Source/Filtering/imstkImageResample.h b/Source/Filtering/imstkImageResample.h new file mode 100644 index 0000000000000000000000000000000000000000..725f3eca26052648ed7e7d9ec4c58b9fe268bde2 --- /dev/null +++ b/Source/Filtering/imstkImageResample.h @@ -0,0 +1,57 @@ +/*========================================================================= + + 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 "imstkGeometryAlgorithm.h" +#include "imstkMath.h" + +namespace imstk +{ +class ImageData; + +/// +/// \class ImageResample +/// +/// \brief Trilinearly Resamples a 3d image to different dimensions +/// +class ImageResample : public GeometryAlgorithm +{ +public: + ImageResample(); + + virtual ~ImageResample() override = default; + +public: + std::shared_ptr<ImageData> getOutputImage() const; + + void setInputImage(std::shared_ptr<ImageData> inputData); + + imstkGetMacro(Dimensions, const Vec3i&); + + imstkSetMacro(Dimensions, const Vec3i&); + +protected: + void requestUpdate() override; + +private: + Vec3i m_Dimensions; +}; +} \ No newline at end of file diff --git a/Source/Filtering/imstkImplicitGeometryToImageData.cpp b/Source/Filtering/imstkImplicitGeometryToImageData.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b1f43c4828ca9dfb68def9849ee8edcc41c5819e --- /dev/null +++ b/Source/Filtering/imstkImplicitGeometryToImageData.cpp @@ -0,0 +1,91 @@ +/*========================================================================= + + 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 "imstkImplicitGeometryToImageData.h" +#include "imstkImageData.h" +#include "imstkLogger.h" +#include "imstkGeometryUtilities.h" +#include "imstkImplicitGeometry.h" +#include "imstkDataArray.h" + +namespace imstk +{ +ImplicitGeometryToImageData::ImplicitGeometryToImageData() +{ + setNumberOfInputPorts(1); + setNumberOfOutputPorts(1); + setOutput(std::make_shared<ImageData>()); +} + +std::shared_ptr<ImageData> +ImplicitGeometryToImageData::getOutputImage() const +{ + return std::dynamic_pointer_cast<ImageData>(getOutput(0)); +} + +void +ImplicitGeometryToImageData::setInputGeometry(std::shared_ptr<ImplicitGeometry> inputGeometry) +{ + setInput(inputGeometry, 0); +} + +void +ImplicitGeometryToImageData::requestUpdate() +{ + std::shared_ptr<ImplicitGeometry> inputGeometry = std::dynamic_pointer_cast<ImplicitGeometry>(getInput(0)); + if (inputGeometry == nullptr) + { + LOG(WARNING) << "No inputGeometry to rasterize"; + return; + } + + if (m_Dimensions[0] == 0 || m_Dimensions[1] == 0 || m_Dimensions[2] == 0) + { + LOG(WARNING) << "Dimensions must be non-zero"; + return; + } + + const Vec3d size = Vec3d(m_Bounds[1] - m_Bounds[0], m_Bounds[3] - m_Bounds[2], m_Bounds[5] - m_Bounds[4]); + const Vec3d spacing = size.cwiseQuotient(m_Dimensions.cast<double>()); + const Vec3d origin = Vec3d(m_Bounds[0], m_Bounds[2], m_Bounds[4]); + const Vec3d shift = origin + spacing * 0.5; + + std::shared_ptr<ImageData> outputImage = std::make_shared<ImageData>(); + outputImage->allocate(IMSTK_DOUBLE, 1, m_Dimensions, spacing, origin); + DataArray<double>& scalars = *std::dynamic_pointer_cast<DataArray<double>>(outputImage->getScalars()); + double* imgPtr = scalars.getPointer(); + + int i = 0; + for (int z = 0; z < m_Dimensions[2]; z++) + { + for (int y = 0; y < m_Dimensions[1]; y++) + { + for (int x = 0; x < m_Dimensions[0]; x++, i++) + { + const Vec3d pos = Vec3d(x, y, z).cwiseProduct(spacing) + shift; + imgPtr[i] = inputGeometry->getFunctionValue(pos); + } + } + } + + setOutput(outputImage); +} +} \ No newline at end of file diff --git a/Source/Filtering/imstkImplicitGeometryToImageData.h b/Source/Filtering/imstkImplicitGeometryToImageData.h new file mode 100644 index 0000000000000000000000000000000000000000..77c399849b72d7447bc891991646439f3f3e71dc --- /dev/null +++ b/Source/Filtering/imstkImplicitGeometryToImageData.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. + +=========================================================================*/ +#pragma once + +#include "imstkGeometryAlgorithm.h" +#include "imstkMath.h" + +namespace imstk +{ +class ImageData; +class ImplicitGeometry; + +/// +/// \class ImplicitGeometryToImageData +/// +/// \brief This filter rasterizes an implicit function to image of +/// specified dimensions and bounds +/// +class ImplicitGeometryToImageData : public GeometryAlgorithm +{ +public: + ImplicitGeometryToImageData(); + virtual ~ImplicitGeometryToImageData() override = default; + +public: + std::shared_ptr<ImageData> getOutputImage() const; + + /// + /// \brief Required input, port 0 + /// + void setInputGeometry(std::shared_ptr<ImplicitGeometry> inputGeometry); + + imstkGetMacro(Dimensions, const Vec3i&); + imstkGetMacro(Bounds, const Vec6d&); + + imstkSetMacro(Dimensions, const Vec3i&); + imstkSetMacro(Bounds, const Vec6d&); + +protected: + void requestUpdate() override; + +private: + Vec3i m_Dimensions; + Vec6d m_Bounds; +}; +} \ No newline at end of file diff --git a/Source/Filtering/imstkQuadricDecimate.cpp b/Source/Filtering/imstkQuadricDecimate.cpp new file mode 100644 index 0000000000000000000000000000000000000000..38facf819d512705607aa0cc5c81b51260a419ca --- /dev/null +++ b/Source/Filtering/imstkQuadricDecimate.cpp @@ -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. + +=========================================================================*/ + +#include "imstkQuadricDecimate.h" +#include "imstkSurfaceMesh.h" +#include "imstkLogger.h" +#include "imstkGeometryUtilities.h" + +#include <vtkQuadricDecimation.h> + +namespace imstk +{ +QuadricDecimate::QuadricDecimate() : + m_VolumePreserving(true), m_TargetReduction(0.6) +{ + setNumberOfInputPorts(1); + setNumberOfOutputPorts(1); + setOutput(std::make_shared<SurfaceMesh>()); +} + +void +QuadricDecimate::setInputMesh(std::shared_ptr<SurfaceMesh> inputMesh) +{ + setInput(inputMesh, 0); +} + +void +QuadricDecimate::requestUpdate() +{ + std::shared_ptr<SurfaceMesh> inputMesh = std::dynamic_pointer_cast<SurfaceMesh>(getInput(0)); + if (inputMesh == nullptr) + { + LOG(WARNING) << "No inputMesh to clean"; + return; + } + vtkSmartPointer<vtkPolyData> inputMeshVtk = GeometryUtils::copyToVtkPolyData(std::dynamic_pointer_cast<SurfaceMesh>(inputMesh)); + + vtkNew<vtkQuadricDecimation> filter; + filter->SetInputData(inputMeshVtk); + filter->SetVolumePreservation(m_VolumePreserving); + filter->SetTargetReduction(m_TargetReduction); + filter->Update(); + + setOutput(GeometryUtils::copyToSurfaceMesh(filter->GetOutput())); +} +} \ No newline at end of file diff --git a/Source/Filtering/imstkQuadricDecimate.h b/Source/Filtering/imstkQuadricDecimate.h new file mode 100644 index 0000000000000000000000000000000000000000..6bb4d3ff28ee6dbb942178003c2231405d808479 --- /dev/null +++ b/Source/Filtering/imstkQuadricDecimate.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. + +=========================================================================*/ +#pragma once + +#include "imstkGeometryAlgorithm.h" + +namespace imstk +{ +class SurfaceMesh; + +/// +/// \class CleanMesh +/// +/// \brief This filter reduces a SurfaceMesh +/// +class QuadricDecimate : public GeometryAlgorithm +{ +public: + QuadricDecimate(); + virtual ~QuadricDecimate() override = default; + +public: + /// + /// \brief Required input, port 0 + /// + void setInputMesh(std::shared_ptr<SurfaceMesh> inputMesh); + + imstkGetMacro(VolumePreserving, bool); + imstkGetMacro(TargetReduction, double); + + /// + /// \brief Set whether to preserve volume or not, default on + /// + imstkSetMacro(VolumePreserving, bool); + + /// + /// \brief Set the target reduction ratio + /// + imstkSetMacro(TargetReduction, double); + +protected: + void requestUpdate() override; + +private: + bool m_VolumePreserving; + double m_TargetReduction; +}; +} \ No newline at end of file diff --git a/Source/Filtering/imstkSelectEnclosedPoints.cpp b/Source/Filtering/imstkSelectEnclosedPoints.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c90178cd8cba24da3aa0a3f5a0505645769d6920 --- /dev/null +++ b/Source/Filtering/imstkSelectEnclosedPoints.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 "imstkSelectEnclosedPoints.h" +#include "imstkGeometryUtilities.h" +#include "imstkLogger.h" +#include "imstkSurfaceMesh.h" + +#include <vtkPolyData.h> +#include <vtkSelectEnclosedPoints.h> + +namespace imstk +{ +SelectEnclosedPoints::SelectEnclosedPoints() +{ + setNumberOfInputPorts(2); + setNumberOfOutputPorts(1); + setOutput(std::make_shared<PointSet>()); +} + +void +SelectEnclosedPoints::setInputMesh(std::shared_ptr<SurfaceMesh> inputMesh) +{ + setInput(inputMesh, 0); +} + +void +SelectEnclosedPoints::setInputPoints(std::shared_ptr<PointSet> inputPts) +{ + setInput(inputPts, 1); +} + +std::shared_ptr<PointSet> +SelectEnclosedPoints::getOutputPoints() const +{ + return std::static_pointer_cast<PointSet>(getOutput(0)); +} + +void +SelectEnclosedPoints::requestUpdate() +{ + std::shared_ptr<SurfaceMesh> inputSurfaceMesh = std::dynamic_pointer_cast<SurfaceMesh>(getInput(0)); + std::shared_ptr<PointSet> inputPointSet = std::dynamic_pointer_cast<PointSet>(getInput(1)); + m_IsInsideMask = nullptr; + + if (inputSurfaceMesh == nullptr || inputPointSet == nullptr) + { + LOG(WARNING) << "Missing inputs"; + return; + } + + vtkNew<vtkSelectEnclosedPoints> filter; + filter->SetInputData(GeometryUtils::copyToVtkPointSet(inputPointSet)); + filter->SetSurfaceData(GeometryUtils::copyToVtkPolyData(inputSurfaceMesh)); + filter->SetTolerance(m_Tolerance); + filter->SetInsideOut(m_InsideOut); + filter->Update(); + + vtkSmartPointer<vtkPointSet> vtkResults = vtkPointSet::SafeDownCast(filter->GetOutput()); + + if (m_UsePruning) + { + StdVectorOfVec3d points; + points.reserve(vtkResults->GetNumberOfPoints()); + for (vtkIdType i = 0; i < vtkResults->GetNumberOfPoints(); i++) + { + if (filter->IsInside(i)) + { + double pt[3]; + vtkResults->GetPoint(i, pt); + points.push_back(Vec3d(pt[0], pt[1], pt[2])); + } + } + points.shrink_to_fit(); + + std::shared_ptr<PointSet> results = std::make_shared<PointSet>(); + results->setInitialVertexPositions(points); + results->setVertexPositions(points); + setOutput(results, 0); + } + else + { + m_IsInsideMask = std::make_shared<DataArray<unsigned char>>(vtkResults->GetNumberOfPoints()); + DataArray<unsigned char>& mask = *m_IsInsideMask; + for (vtkIdType i = 0; i < vtkResults->GetNumberOfPoints(); i++) + { + mask[i] = filter->IsInside(i); + } + } +} +} \ No newline at end of file diff --git a/Source/Filtering/imstkSelectEnclosedPoints.h b/Source/Filtering/imstkSelectEnclosedPoints.h new file mode 100644 index 0000000000000000000000000000000000000000..f92beb590b88efe902610a20f19f5f07ef3a3198 --- /dev/null +++ b/Source/Filtering/imstkSelectEnclosedPoints.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. + +=========================================================================*/ +#pragma once + +#include "imstkGeometryAlgorithm.h" +#include "imstkDataArray.h" + +namespace imstk +{ +class PointSet; +class SurfaceMesh; + +/// +/// \class CleanMesh +/// +/// \brief This filter will select the points within a surfacemesh. It can +/// either prune or return the mask +/// +class SelectEnclosedPoints : public GeometryAlgorithm +{ +public: + SelectEnclosedPoints(); + virtual ~SelectEnclosedPoints() override = default; + +public: + void setInputMesh(std::shared_ptr<SurfaceMesh> inputMesh); + void setInputPoints(std::shared_ptr<PointSet> inputPoints); + std::shared_ptr<PointSet> getOutputPoints() const; + + imstkGetMacro(UsePruning, bool); + imstkGetMacro(Tolerance, double); + imstkGetMacro(InsideOut, bool); + imstkGetMacro(IsInsideMask, std::shared_ptr<DataArray<unsigned char>>); + + imstkSetMacro(UsePruning, bool); + imstkSetMacro(Tolerance, double); + imstkSetMacro(InsideOut, bool); + +protected: + void requestUpdate() override; + +private: + bool m_UsePruning = true; + double m_Tolerance = 0.0; + bool m_InsideOut = false; + std::shared_ptr<DataArray<unsigned char>> m_IsInsideMask = nullptr; +}; +} \ No newline at end of file diff --git a/Source/Filtering/imstkSurfaceMeshDistanceTransform.cpp b/Source/Filtering/imstkSurfaceMeshDistanceTransform.cpp new file mode 100644 index 0000000000000000000000000000000000000000..373eeca50ea254941d9054ffbd5f120ac49d8e02 --- /dev/null +++ b/Source/Filtering/imstkSurfaceMeshDistanceTransform.cpp @@ -0,0 +1,250 @@ +/*========================================================================= + + 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 "imstkSurfaceMeshDistanceTransform.h" +#include "imstkDataArray.h" +#include "imstkGeometryUtilities.h" +#include "imstkImageData.h" +#include "imstkLogger.h" +#include "imstkLooseOctree.h" +#include "imstkParallelUtils.h" +#include "imstkSurfaceMesh.h" +#include "imstkTimer.h" +#include "imstkSurfaceMeshImageMask.h" +#include <stack> +#include <vtkDistancePolyDataFilter.h> +#include <vtkImageData.h> +#include <vtkImplicitPolyDataDistance.h> +#include <vtkOctreePointLocator.h> +#include <vtkPointData.h> +#include <vtkPolyData.h> +#include <vtkSelectEnclosedPoints.h> + +namespace imstk +{ +//static bool neighborNotEqual(const Vec3i& pt, const Vec3i& dim, const float val, const float* imgPtr) +//{ +// const Vec3i ptc = pt.cwiseMax(0).cwiseMin(dim - Vec3i(1, 1, 1)); +// const Vec3i minima = (pt - Vec3i(1, 1, 1)).cwiseMax(0).cwiseMin(dim - Vec3i(1, 1, 1)); +// const Vec3i maxima = (pt + Vec3i(1, 1, 1)).cwiseMax(0).cwiseMin(dim - Vec3i(1, 1, 1)); +// +// const size_t xIndex1 = ImageData::getScalarIndex(minima[0], ptc[1], ptc[2], dim, 1); +// const size_t xIndex2 = ImageData::getScalarIndex(maxima[0], ptc[1], ptc[2], dim, 1); +// const size_t yIndex1 = ImageData::getScalarIndex(ptc[0], minima[1], ptc[2], dim, 1); +// const size_t yIndex2 = ImageData::getScalarIndex(ptc[0], maxima[1], ptc[2], dim, 1); +// const size_t zIndex1 = ImageData::getScalarIndex(ptc[0], ptc[1], minima[2], dim, 1); +// const size_t zIndex2 = ImageData::getScalarIndex(ptc[0], ptc[1], maxima[2], dim, 1); +// +// if (imgPtr[xIndex1] != val) +// return true; +// if (imgPtr[xIndex2] != val) +// return true; +// if (imgPtr[yIndex1] != val) +// return true; +// if (imgPtr[yIndex2] != val) +// return true; +// if (imgPtr[zIndex1] != val) +// return true; +// if (imgPtr[zIndex2] == val) +// return true; +// return false; +//} + +//// Narrow band is WIP, it works but is slow +//static void +//computeNarrowBandedDT(std::shared_ptr<ImageData> imageData, std::shared_ptr<SurfaceMesh> surfMesh, double bandwidth) +//{ +// // Rasterize a mask from the polygon +// std::shared_ptr<SurfaceMeshImageMask> imageMask = std::make_shared<SurfaceMeshImageMask>(); +// imageMask->setInputMesh(surfMesh); +// imageMask->setReferenceImage(imageData); +// imageMask->update(); +// +// DataArray<float>& inputScalars = *std::dynamic_pointer_cast<DataArray<float>>(imageMask->getOutputImage()->getScalars()); +// float* inputImgPtr = inputScalars.getPointer(); +// DataArray<float>& outputScalars = *std::dynamic_pointer_cast<DataArray<float>>(imageData->getScalars()); +// float* outputImgPtr = outputScalars.getPointer(); +// +// vtkSmartPointer<vtkPolyData> inputPolyData = GeometryUtils::copyToVtkPolyData(surfMesh); +// vtkSmartPointer<vtkImplicitPolyDataDistance> polyDataDist = vtkSmartPointer<vtkImplicitPolyDataDistance>::New(); +// polyDataDist->SetInput(inputPolyData); +// std::fill_n(outputImgPtr, outputScalars.size(), VTK_FLOAT_MIN); +// +// // Iterate the image testing for boundary pixels (ie any 0 adjacent to a 1) +// const Vec3i& dim = imageData->getDimensions(); +// const Vec3d shift = imageData->getOrigin() + imageData->getSpacing() * 0.5; +// const Vec3d& spacing = imageData->getSpacing(); +// int i = 0; +// for (int z = 0; z < dim[2]; z++) +// { +// for (int y = 0; y < dim[1]; y++) +// { +// for (int x = 0; x < dim[0]; x++, i++) +// { +// const float val = inputImgPtr[i]; +// const Vec3i pt = Vec3i(x, y, z); +// if (neighborNotEqual(pt, dim, val, inputImgPtr)) +// { +// const Vec3d pos = pt.cast<double>().cwiseProduct(spacing) + shift; +// const float dist = polyDataDist->FunctionValue(pos.data()); +// //printf("%f\n", dist); +// outputImgPtr[i] = dist; +// } +// else if (val == 0.0f) +// { +// outputImgPtr[i] = VTK_FLOAT_MIN; +// } +// } +// } +// } +//} + +static void +computeFullDT(std::shared_ptr<ImageData> imageData, std::shared_ptr<SurfaceMesh> surfMesh) +{ + // Get the optimal number of threads + const size_t numThreads = ParallelUtils::ThreadManager::getThreadPoolSize(); + + const Vec3i& dim = imageData->getDimensions(); + const Vec3d spacing = imageData->getSpacing(); + const Vec3d shift = imageData->getOrigin() + spacing * 0.5; + + DataArray<double>& scalars = *static_cast<DataArray<double>*>(imageData->getScalars().get()); + + // Split the work up along z using thread count to avoid making too many octtrees (may not be most optimal) + ParallelUtils::parallelFor(numThreads, [&](const size_t& i) + { + // Separate polygons used to avoid race conditions + vtkSmartPointer<vtkPolyData> inputPolyData = GeometryUtils::copyToVtkPolyData(surfMesh); + vtkSmartPointer<vtkImplicitPolyDataDistance> polyDataDist = vtkSmartPointer<vtkImplicitPolyDataDistance>::New(); + polyDataDist->SetInput(inputPolyData); + for (int z = static_cast<int>(i); z < dim[2]; z += static_cast<int>(numThreads)) + { + int j = z * dim[0] * dim[1]; + for (int y = 0; y < dim[1]; y++) + { + for (int x = 0; x < dim[0]; x++, j++) + { + double pos[3] = { x* spacing[0] + shift[0], y * spacing[1] + shift[1], z * spacing[2] + shift[2] }; + scalars[j] = polyDataDist->FunctionValue(pos); + } + } + } + }); + + // Sequential implementation + /*vtkSmartPointer<vtkPolyData> inputPolyData = GeometryUtils::copyToVtkPolyData(surfMesh); + vtkSmartPointer<vtkImplicitPolyDataDistance> polyDataDist = vtkSmartPointer<vtkImplicitPolyDataDistance>::New(); + polyDataDist->SetInput(inputPolyData); + int j = 0; + for (int z = 0; z < dim[2]; z++) + { + for (int y = 0; y < dim[1]; y++) + { + for (int x = 0; x < dim[0]; x++, j++) + { + double pos[3] = { x * spacing[0] + shift[0], y * spacing[1] + shift[1], z * spacing[2] + shift[2] }; + scalars[j] = polyDataDist->FunctionValue(pos); + } + } + }*/ +} + +SurfaceMeshDistanceTransform::SurfaceMeshDistanceTransform() +{ + setNumberOfInputPorts(1); + setNumberOfOutputPorts(1); + setOutput(std::make_shared<ImageData>(), 0); +} + +void +SurfaceMeshDistanceTransform::setInputMesh(std::shared_ptr<SurfaceMesh> mesh) +{ + setInput(mesh, 0); +} + +std::shared_ptr<ImageData> +SurfaceMeshDistanceTransform::getOutputImage() +{ + return std::dynamic_pointer_cast<ImageData>(getOutput()); +} + +void +SurfaceMeshDistanceTransform::requestUpdate() +{ + std::shared_ptr<SurfaceMesh> inputSurfaceMesh = std::dynamic_pointer_cast<SurfaceMesh>(getInput(0)); + std::shared_ptr<ImageData> outputImageData = std::dynamic_pointer_cast<ImageData>(getOutput(0)); + + if (inputSurfaceMesh == nullptr) + { + LOG(WARNING) << "Missing input surface mesh"; + return; + } + + if (m_Dimensions[0] == 0 || m_Dimensions[1] == 0 || m_Dimensions[2] == 0) + { + LOG(WARNING) << "Dimensions not set"; + return; + } + + // Allocate an image for it + Vec3d min; + Vec3d max; + inputSurfaceMesh->computeBoundingBox(min, max); + double bounds[6]; + if (m_UseBounds) + { + 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 size = Vec3d(bounds[1] - bounds[0], bounds[3] - bounds[2], bounds[5] - bounds[4]); + Vec3d spacing = size.cwiseQuotient(m_Dimensions.cast<double>()); + Vec3d origin = Vec3d(bounds[0], bounds[2], bounds[4]); + outputImageData->allocate(IMSTK_DOUBLE, 1, m_Dimensions, spacing, origin); + + /* StopWatch timer; + timer.start();*/ + + /*if (NarrowBanded) + { + computeNarrowBandedDT(outputImageData, inputSurfaceMesh, NarrowBandWidth); + } + else*/ + { + computeFullDT(outputImageData, inputSurfaceMesh); + } + + //printf("time: %f\n", timer.getTimeElapsed()); +} +} \ No newline at end of file diff --git a/Source/Filtering/imstkSurfaceMeshDistanceTransform.h b/Source/Filtering/imstkSurfaceMeshDistanceTransform.h new file mode 100644 index 0000000000000000000000000000000000000000..726110c019b4b012d1767ecadc5fed1185bd04ef --- /dev/null +++ b/Source/Filtering/imstkSurfaceMeshDistanceTransform.h @@ -0,0 +1,92 @@ +/*========================================================================= + + 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 "imstkGeometryAlgorithm.h" +#include "imstkMath.h" + +namespace imstk +{ +class ImageData; +class SurfaceMesh; + +/// +/// \class SurfaceMeshDistanceTransform +/// +/// \brief This filter computes brute force signed distance field by computing the nearest +/// point in one dataset to the other +/// +class SurfaceMeshDistanceTransform : public GeometryAlgorithm +{ +public: + SurfaceMeshDistanceTransform(); + virtual ~SurfaceMeshDistanceTransform() override = default; + +public: + /// + /// \brief Required input, port 0 + /// + void setInputMesh(std::shared_ptr<SurfaceMesh> surfMesh); + + std::shared_ptr<ImageData> getOutputImage(); + + imstkGetMacro(Dimensions, const Vec3i&); + imstkGetMacro(Bounds, const Vec6d&); + imstkGetMacro(UseBounds, bool); + //imstkGetMacro(NarrowBanded, bool); + //imstkGetMacro(NarrowBandWidth, double); + + /// + /// \brief Dimensions of distance transform to fill + /// + imstkSetMacro(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); + + /// + /// \brief If on, will compute only a narrow banded transform + /// + //imstkSetMacro(NarrowBanded, bool); + + /// + /// \brief Width of the band + /// + //imstkSetMacro(NarrowBandWidth, double); + + void setDimensions(int dimX, int dimY, int dimZ) { setDimensions(Vec3i(dimX, dimY, dimZ)); } + +protected: + void requestUpdate() override; + +private: + Vec3i m_Dimensions = Vec3i(0, 0, 0); + Vec6d m_Bounds; + bool m_UseBounds = false; + //bool m_NarrowBanded = false; + //double m_NarrowBandWidth = 1.0; +}; +} \ No newline at end of file diff --git a/Source/Filtering/imstkSurfaceMeshFlyingEdges.cpp b/Source/Filtering/imstkSurfaceMeshFlyingEdges.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a2878882e0fc827ee0549a05a4385dd69d255852 --- /dev/null +++ b/Source/Filtering/imstkSurfaceMeshFlyingEdges.cpp @@ -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. + +=========================================================================*/ + +#include "imstkSurfaceMeshFlyingEdges.h" +#include "imstkGeometryUtilities.h" +#include "imstkImageData.h" +#include "imstkLogger.h" +#include "imstkSurfaceMesh.h" + +#include <vtkFlyingEdges3D.h> +#include <vtkImageData.h> + +namespace imstk +{ +SurfaceMeshFlyingEdges::SurfaceMeshFlyingEdges() +{ + setNumberOfInputPorts(1); + setNumberOfOutputPorts(1); + setOutput(std::make_shared<SurfaceMesh>()); +} + +void +SurfaceMeshFlyingEdges::setInputImage(std::shared_ptr<ImageData> inputImage) +{ + setInput(inputImage, 0); +} + +std::shared_ptr<SurfaceMesh> +SurfaceMeshFlyingEdges::getOutputMesh() const +{ + return std::dynamic_pointer_cast<SurfaceMesh>(getOutput(0)); +} + +void +SurfaceMeshFlyingEdges::requestUpdate() +{ + std::shared_ptr<ImageData> inputImage = std::dynamic_pointer_cast<ImageData>(getInput(0)); + if (inputImage == nullptr) + { + LOG(WARNING) << "No inputImage to extract isosurface from"; + return; + } + + vtkNew<vtkFlyingEdges3D> filter; + filter->SetInputData(GeometryUtils::coupleVtkImageData(inputImage)); + filter->SetValue(0, m_IsoValue); + filter->Update(); + + setOutput(GeometryUtils::copyToSurfaceMesh(filter->GetOutput())); +} +} \ No newline at end of file diff --git a/Source/Filtering/imstkSurfaceMeshFlyingEdges.h b/Source/Filtering/imstkSurfaceMeshFlyingEdges.h new file mode 100644 index 0000000000000000000000000000000000000000..df2c6475a473aa6dfd10e18e76f792a2d45e14c0 --- /dev/null +++ b/Source/Filtering/imstkSurfaceMeshFlyingEdges.h @@ -0,0 +1,62 @@ +/*========================================================================= + + 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 "imstkGeometryAlgorithm.h" + +namespace imstk +{ +class ImageData; +class SurfaceMesh; + +/// +/// \class SurfaceMeshFlyingEdges +/// +/// \brief This filter extracts a single isocontour from an imstkImageData +/// +class SurfaceMeshFlyingEdges : public GeometryAlgorithm +{ +public: + SurfaceMeshFlyingEdges(); + virtual ~SurfaceMeshFlyingEdges() override = default; + +public: + /// + /// \brief Required input, port 0 + /// + void setInputImage(std::shared_ptr<ImageData> inputImage); + + std::shared_ptr<SurfaceMesh> getOutputMesh() const; + + imstkGetMacro(IsoValue, double); + + /// + /// \brief Get the value at which the surface should be produced + /// + imstkSetMacro(IsoValue, double); + +protected: + void requestUpdate() override; + +private: + double m_IsoValue = 0.0; +}; +} \ No newline at end of file diff --git a/Source/Filtering/imstkSurfaceMeshImageMask.cpp b/Source/Filtering/imstkSurfaceMeshImageMask.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6ea1dc12b74cb0abe4d8c100dbbc25cc8ecb65a0 --- /dev/null +++ b/Source/Filtering/imstkSurfaceMeshImageMask.cpp @@ -0,0 +1,148 @@ +/*========================================================================= + + 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 "imstkSurfaceMeshImageMask.h" +#include "imstkCleanMesh.h" +#include "imstkGeometryUtilities.h" +#include "imstkImageData.h" +#include "imstkLogger.h" +#include "imstkSurfaceMesh.h" + +#include <vtkImageData.h> +#include <vtkImageStencil.h> +#include <vtkPolyData.h> +#include <vtkPolyDataToImageStencil.h> + +namespace imstk +{ +SurfaceMeshImageMask::SurfaceMeshImageMask() +{ + setNumberOfInputPorts(2); + setNumberOfOutputPorts(1); + setOutput(std::make_shared<ImageData>(), 0); +} + +void +SurfaceMeshImageMask::setReferenceImage(std::shared_ptr<ImageData> refImage) +{ + setInput(refImage, 1); +} + +void +SurfaceMeshImageMask::setInputMesh(std::shared_ptr<SurfaceMesh> mesh) +{ + setInput(mesh, 0); +} + +std::shared_ptr<ImageData> +SurfaceMeshImageMask::getOutputImage() const +{ + return std::static_pointer_cast<ImageData>(getOutput(0)); +} + +void +SurfaceMeshImageMask::requestUpdate() +{ + std::shared_ptr<SurfaceMesh> surfMeshInput = std::dynamic_pointer_cast<SurfaceMesh>(getInput(0)); + std::shared_ptr<ImageData> refImageInput = std::dynamic_pointer_cast<ImageData>(getInput(1)); + + if (surfMeshInput == nullptr) + { + LOG(WARNING) << "Missing input surface mesh"; + return; + } + + Vec3d spacing; + int extent[6]; + Vec3d origin; + if (refImageInput != nullptr) + { + spacing = refImageInput->getSpacing(); + + origin = refImageInput->getOrigin(); + + const Vec3i& dim = refImageInput->getDimensions(); + extent[0] = 0; + extent[1] = dim[0]; + extent[2] = 0; + extent[3] = dim[1]; + extent[4] = 0; + extent[5] = dim[2]; + } + else + { + if (m_Dimensions[0] == -1 || m_Dimensions[1] == -1 || m_Dimensions[2] == -1) + { + LOG(WARNING) << "No reference image or desired image dimensions."; + return; + } + Vec3d min; + Vec3d max; + surfMeshInput->computeBoundingBox(min, max); + + Vec3d size = max - min; + + // Compute spacing required for given dimension + spacing = size.cwiseQuotient(m_Dimensions.cast<double>()); + + // Increase bounds by px length + min -= spacing * m_BorderExtent; + max += spacing * m_BorderExtent; + + size = max - min; + + extent[0] = 0; + extent[1] = (m_Dimensions[0] + m_BorderExtent) - 1; + extent[2] = 0; + extent[3] = (m_Dimensions[1] + m_BorderExtent) - 1; + extent[4] = 0; + extent[5] = (m_Dimensions[2] + m_BorderExtent) - 1; + + origin = min - m_BorderExtent * spacing; + } + + // Allocate a new white image + vtkNew<vtkImageData> baseImage; + baseImage->SetSpacing(spacing.data()); + baseImage->SetExtent(extent); + baseImage->SetOrigin(origin.data()); + baseImage->AllocateScalars(VTK_FLOAT, 1); + int* dim = baseImage->GetDimensions(); + std::fill_n(static_cast<float*>(baseImage->GetScalarPointer()), dim[0] * dim[1] * dim[2], 1.0f); + + // Creates a new image mask from this polygon using a reference mask + vtkNew<vtkPolyDataToImageStencil> poly2Stencil; + poly2Stencil->SetInputData(GeometryUtils::copyToVtkPolyData(surfMeshInput)); + poly2Stencil->SetOutputOrigin(origin.data()); + poly2Stencil->SetOutputSpacing(spacing.data()); + poly2Stencil->SetOutputWholeExtent(extent); + poly2Stencil->Update(); + vtkNew<vtkImageStencil> imgStencil; + imgStencil->SetInputData(baseImage); + imgStencil->SetStencilData(poly2Stencil->GetOutput()); + imgStencil->ReverseStencilOff(); + imgStencil->SetBackgroundValue(0.0); + imgStencil->Update(); + + // Set the output + setOutput(GeometryUtils::copyToImageData(imgStencil->GetOutput())); +} +} \ No newline at end of file diff --git a/Source/Filtering/imstkSurfaceMeshImageMask.h b/Source/Filtering/imstkSurfaceMeshImageMask.h new file mode 100644 index 0000000000000000000000000000000000000000..f5f7b6c8398ffeb4559c900384f9b6ca98e96957 --- /dev/null +++ b/Source/Filtering/imstkSurfaceMeshImageMask.h @@ -0,0 +1,79 @@ +/*========================================================================= + + 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 "imstkGeometryAlgorithm.h" +#include "imstkMath.h" + +namespace imstk +{ +class ImageData; +class SurfaceMesh; + +/// +/// \class ImagePolyDataMask +/// +/// \brief This filter generates a binary mask from input surface mesh. Optionally +/// one may provide a reference image for which to use its spacing, origin, dimensions +/// It can also work with some geometry that is non-manifold, but results are ambiguous +/// +class SurfaceMeshImageMask : public GeometryAlgorithm +{ +public: + SurfaceMeshImageMask(); + virtual ~SurfaceMeshImageMask() override = default; + +public: + /// + /// \brief Optional input, used for information (dimensions, spacing, etc) + /// + void setReferenceImage(std::shared_ptr<ImageData> refImage); + void setInputMesh(std::shared_ptr<SurfaceMesh> mesh); + std::shared_ptr<ImageData> getOutputImage() const; + + imstkGetMacro(BorderExtent, int); + imstkGetMacro(Dimensions, const Vec3i&); + + /// + /// \brief Adds a border around the generated image of pixel amount + /// border exists outside of bounds + /// + imstkSetMacro(BorderExtent, int); + + /// + /// \brief The dimensions of the image to generate + /// + imstkSetMacro(Dimensions, const Vec3i&); + + /// + /// \brief The dimensions of the image to generate + /// + void setDimensions(int dimX, int dimY, int dimZ) { setDimensions(Vec3i(dimX, dimY, dimZ)); } + +protected: + void requestUpdate() override; + +private: + Vec3i m_Dimensions = Vec3i(-1, -1, -1); + int m_BorderExtent = 1; + bool m_CheckManifold = true; +}; +} \ No newline at end of file diff --git a/Source/Filtering/imstkSurfaceMeshSmoothen.cpp b/Source/Filtering/imstkSurfaceMeshSmoothen.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8d628bcccb0ffc4b2b8d993d563d0e5bd0352b7f --- /dev/null +++ b/Source/Filtering/imstkSurfaceMeshSmoothen.cpp @@ -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. + +=========================================================================*/ + +#include "imstkSurfaceMeshSmoothen.h" +#include "imstkGeometryUtilities.h" +#include "imstkLogger.h" +#include "imstkSurfaceMesh.h" + +#include <vtkSmoothPolyDataFilter.h> + +namespace imstk +{ +SurfaceMeshSmoothen::SurfaceMeshSmoothen() +{ + setNumberOfInputPorts(1); + setNumberOfOutputPorts(1); + setOutput(std::make_shared<SurfaceMesh>()); +} + +void +SurfaceMeshSmoothen::setInputMesh(std::shared_ptr<SurfaceMesh> inputMesh) +{ + setInput(inputMesh, 0); +} + +void +SurfaceMeshSmoothen::requestUpdate() +{ + std::shared_ptr<SurfaceMesh> inputMesh = std::dynamic_pointer_cast<SurfaceMesh>(getInput(0)); + if (inputMesh == nullptr) + { + LOG(WARNING) << "No inputMesh to smoothen"; + return; + } + + vtkNew<vtkSmoothPolyDataFilter> filter; + filter->SetInputData(GeometryUtils::copyToVtkPolyData(inputMesh)); + filter->SetNumberOfIterations(m_NumberOfIterations); + filter->SetRelaxationFactor(m_RelaxationFactor); + filter->SetConvergence(m_Convergence); + filter->SetFeatureAngle(m_FeatureAngle); + filter->SetEdgeAngle(m_EdgeAngle); + filter->SetFeatureEdgeSmoothing(m_FeatureEdgeSmoothing); + filter->SetBoundarySmoothing(m_BoundarySmoothing); + filter->Update(); + + setOutput(GeometryUtils::copyToSurfaceMesh(filter->GetOutput())); +} +} \ No newline at end of file diff --git a/Source/Filtering/imstkSurfaceMeshSmoothen.h b/Source/Filtering/imstkSurfaceMeshSmoothen.h new file mode 100644 index 0000000000000000000000000000000000000000..6f59bd37b45a2b9e947e9ff059d80fa7cde827ac --- /dev/null +++ b/Source/Filtering/imstkSurfaceMeshSmoothen.h @@ -0,0 +1,75 @@ +/*========================================================================= + + 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 "imstkGeometryAlgorithm.h" + +namespace imstk +{ +class SurfaceMesh; + +/// +/// \class SurfaceMeshSmoothen +/// +/// \brief This filter smoothes the input SurfaceMesh currently only laplacian +/// smoothing is provided +/// +class SurfaceMeshSmoothen : public GeometryAlgorithm +{ +public: + SurfaceMeshSmoothen(); + virtual ~SurfaceMeshSmoothen() override = default; + +public: + imstkGetMacro(NumberOfIterations, int); + imstkGetMacro(RelaxationFactor, double); + imstkGetMacro(Convergence, double); + imstkGetMacro(FeatureAngle, double); + imstkGetMacro(EdgeAngle, double); + imstkGetMacro(FeatureEdgeSmoothing, bool); + imstkGetMacro(BoundarySmoothing, bool); + + /// + /// \brief Required input, port 0 + /// + void setInputMesh(std::shared_ptr<SurfaceMesh> inputMesh); + + imstkSetMacro(NumberOfIterations, int); + imstkSetMacro(RelaxationFactor, double); + imstkSetMacro(Convergence, double); + imstkSetMacro(FeatureAngle, double); + imstkSetMacro(EdgeAngle, double); + imstkSetMacro(FeatureEdgeSmoothing, bool); + imstkSetMacro(BoundarySmoothing, bool); + +protected: + void requestUpdate() override; + +private: + int m_NumberOfIterations = 20; + double m_RelaxationFactor = 0.01; + double m_Convergence = 0.0; + double m_FeatureAngle = 45.0; + double m_EdgeAngle = 15.0; + bool m_FeatureEdgeSmoothing = false; + bool m_BoundarySmoothing = true; +}; +} \ No newline at end of file diff --git a/Source/Filtering/imstkSurfaceMeshSubdivide.cpp b/Source/Filtering/imstkSurfaceMeshSubdivide.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e3726b7d1e18bc8fe7a36a7935aabaaafbef48a7 --- /dev/null +++ b/Source/Filtering/imstkSurfaceMeshSubdivide.cpp @@ -0,0 +1,83 @@ +/*========================================================================= + + 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 "imstkSurfaceMeshSubdivide.h" +#include "imstkGeometryUtilities.h" +#include "imstkSurfaceMesh.h" +#include "imstkLogger.h" + +#include <vtkButterflySubdivisionFilter.h> +#include <vtkLinearSubdivisionFilter.h> +#include <vtkLoopSubdivisionFilter.h> + +namespace imstk +{ +SurfaceMeshSubdivide::SurfaceMeshSubdivide() +{ + setNumberOfInputPorts(1); + setNumberOfOutputPorts(1); + setOutput(std::make_shared<SurfaceMesh>()); +} + +std::shared_ptr<SurfaceMesh> +SurfaceMeshSubdivide::getOutputMesh() +{ + return std::dynamic_pointer_cast<SurfaceMesh>(getOutput(0)); +} + +void +SurfaceMeshSubdivide::setInputMesh(std::shared_ptr<SurfaceMesh> inputMesh) +{ + setInput(inputMesh, 0); +} + +void +SurfaceMeshSubdivide::requestUpdate() +{ + std::shared_ptr<SurfaceMesh> inputMesh = std::dynamic_pointer_cast<SurfaceMesh>(getInput(0)); + + if (inputMesh == nullptr) + { + LOG(WARNING) << "Missing required SurfaceMesh input"; + return; + } + + vtkSmartPointer<vtkSubdivisionFilter> filter = nullptr; + if (m_SubdivisionType == Type::BUTTERFLY) + { + filter = vtkSmartPointer<vtkButterflySubdivisionFilter>::New(); + } + else if (m_SubdivisionType == Type::LOOP) + { + filter = vtkSmartPointer<vtkLoopSubdivisionFilter>::New(); + } + else + { + filter = vtkSmartPointer<vtkLinearSubdivisionFilter>::New(); + } + + filter->SetInputData(GeometryUtils::copyToVtkPolyData(inputMesh)); + filter->SetNumberOfSubdivisions(m_NumberOfSubdivisions); + filter->Update(); + + setOutput(GeometryUtils::copyToSurfaceMesh(filter->GetOutput())); +} +} \ No newline at end of file diff --git a/Source/Filtering/imstkSurfaceMeshSubdivide.h b/Source/Filtering/imstkSurfaceMeshSubdivide.h new file mode 100644 index 0000000000000000000000000000000000000000..8f4cd6f0fbe252c7658c5ddda0bca1ed0d90175d --- /dev/null +++ b/Source/Filtering/imstkSurfaceMeshSubdivide.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. + +=========================================================================*/ +#pragma once + +#include "imstkGeometryAlgorithm.h" + +namespace imstk +{ +class SurfaceMesh; + +/// +/// \class SubdivideSurfaceMesh +/// +/// \brief This filter subidivdes the triangles of a SurfaceMesh into more +/// smaller triangles +/// \todo: test with LineMesh +/// +class SurfaceMeshSubdivide : public GeometryAlgorithm +{ +public: + enum class Type + { + LINEAR, + LOOP, + BUTTERFLY + }; + +public: + SurfaceMeshSubdivide(); + virtual ~SurfaceMeshSubdivide() override = default; + +public: + std::shared_ptr<SurfaceMesh> getOutputMesh(); + + void setInputMesh(std::shared_ptr<SurfaceMesh> inputMesh); + + imstkGetMacro(SubdivisionType, Type); + imstkGetMacro(NumberOfSubdivisions, int); + imstkSetMacro(SubdivisionType, Type); + imstkSetMacro(NumberOfSubdivisions, int); + +protected: + void requestUpdate() override; + +private: + Type m_SubdivisionType = Type::LINEAR; + int m_NumberOfSubdivisions = 1; +}; +} \ No newline at end of file diff --git a/Source/Geometry/Analytic/imstkAnalyticalGeometry.cpp b/Source/Geometry/Analytic/imstkAnalyticalGeometry.cpp index b0fbb0da50ca990cd1044b886c31ff1db9151b9d..55a61d8c2fac2773dd6d61241af12f624aee7ae1 100644 --- a/Source/Geometry/Analytic/imstkAnalyticalGeometry.cpp +++ b/Source/Geometry/Analytic/imstkAnalyticalGeometry.cpp @@ -20,13 +20,13 @@ =========================================================================*/ #include "imstkAnalyticalGeometry.h" -#include "imstkMath.h" #include "imstkLogger.h" namespace imstk { -AnalyticalGeometry::AnalyticalGeometry(Type type, const std::string& name) : Geometry(type, name), - m_position(WORLD_ORIGIN), m_positionPostTransform(WORLD_ORIGIN), m_orientationAxis(UP_VECTOR), m_orientationAxisPostTransform(UP_VECTOR) +AnalyticalGeometry::AnalyticalGeometry(Type type, const std::string& name) : ImplicitGeometry(type, name), + m_position(WORLD_ORIGIN), m_positionPostTransform(WORLD_ORIGIN), + m_orientationAxis(UP_VECTOR), m_orientationAxisPostTransform(UP_VECTOR) { } diff --git a/Source/Geometry/Analytic/imstkAnalyticalGeometry.h b/Source/Geometry/Analytic/imstkAnalyticalGeometry.h index a58fccc6e0287646ee0d7fac81cb48b1ab137802..905ce45a5da4c31bb12218e715410ceffd14968b 100644 --- a/Source/Geometry/Analytic/imstkAnalyticalGeometry.h +++ b/Source/Geometry/Analytic/imstkAnalyticalGeometry.h @@ -21,7 +21,7 @@ #pragma once -#include "imstkGeometry.h" +#include "imstkImplicitGeometry.h" namespace imstk { @@ -30,10 +30,9 @@ namespace imstk /// /// \brief Base class for any analytical geometrical representation /// -class AnalyticalGeometry : public Geometry +class AnalyticalGeometry : public ImplicitGeometry { public: - /// /// \brief Print /// @@ -54,8 +53,9 @@ public: Vec3d getOrientationAxis(DataType type = DataType::PostTransform); void setOrientationAxis(const Vec3d axis); -protected: + double getFunctionValue(const Vec3d& imstkNotUsed(pos)) const override { return 0.0; } +protected: explicit AnalyticalGeometry(Type type, const std::string& name = std::string("")); /// diff --git a/Source/Geometry/Analytic/imstkCapsule.cpp b/Source/Geometry/Analytic/imstkCapsule.cpp index 5d2a69a21074bf587f20714e80eb51ccd91e6ad0..266fd3e508dd614e0739e28a37db74df1caaaeaf 100644 --- a/Source/Geometry/Analytic/imstkCapsule.cpp +++ b/Source/Geometry/Analytic/imstkCapsule.cpp @@ -20,7 +20,6 @@ =========================================================================*/ #include "imstkCapsule.h" - #include "imstkLogger.h" namespace imstk diff --git a/Source/Geometry/Analytic/imstkCapsule.h b/Source/Geometry/Analytic/imstkCapsule.h index 7191995f1a2b9827e7a95d06dfaaf7475e6578ef..51749ed2f1d5f94fd54ee8b7f074773be4c9181b 100644 --- a/Source/Geometry/Analytic/imstkCapsule.h +++ b/Source/Geometry/Analytic/imstkCapsule.h @@ -21,7 +21,6 @@ #pragma once -// imstk #include "imstkAnalyticalGeometry.h" namespace imstk @@ -72,6 +71,10 @@ public: protected: friend class VTKCapsuleRenderDelegate; + // Hide these unimplemented functions + using AnalyticalGeometry::getFunctionValue; + //using AnalyticalGeometry::getFunctionGrad; + void applyScaling(const double s) override; void updatePostTransformData() const override; diff --git a/Source/Geometry/Analytic/imstkCube.h b/Source/Geometry/Analytic/imstkCube.h index 7291f976957a6e29526da84f07ede79d90c5efde..0ea7bc9e4906a0d7d2020c9762aeb5c1e05e2c92 100644 --- a/Source/Geometry/Analytic/imstkCube.h +++ b/Source/Geometry/Analytic/imstkCube.h @@ -25,6 +25,8 @@ namespace imstk { +class Cube; + /// /// \class Cube /// @@ -33,8 +35,13 @@ namespace imstk class Cube : public AnalyticalGeometry { public: - - explicit Cube(const std::string& name = std::string("")) : AnalyticalGeometry(Type::Cube, name) {} + explicit Cube(const Vec3d& pos = Vec3d(0.0, 0.0, 0.0), const double width = 1.0, const Vec3d& orientationAxis = Vec3d(0.0, 1.0, 0.0), + const std::string& name = std::string("")) : AnalyticalGeometry(Type::Cube, name) + { + setPosition(pos); + setOrientationAxis(orientationAxis); + setWidth(width); + } /// /// \brief Print the cube info @@ -56,6 +63,17 @@ public: /// void setWidth(const double w); + /// + /// \brief Returns signed distance to surface at pos + /// \todo Doesn't support orientation yet + /// + double getFunctionValue(const Vec3d& pos) const override + { + // Make it so that only negatives are within the cube, ie: position so cube's maxima is at origin + const Vec3d d = (pos.cwiseAbs() - m_position) - Vec3d(m_width, m_width, m_width) * 0.5; + return std::min(std::max(d[0], std::max(d[1], d[2])), 0.0) + d.cwiseMax(0.0).norm(); + } + protected: friend class VTKCubeRenderDelegate; diff --git a/Source/Geometry/Analytic/imstkCylinder.cpp b/Source/Geometry/Analytic/imstkCylinder.cpp index 06370c6775c07f2c77d44aa561fb4d6267967f31..887385d3d746242eef1524ec97248cf7ffdfad93 100644 --- a/Source/Geometry/Analytic/imstkCylinder.cpp +++ b/Source/Geometry/Analytic/imstkCylinder.cpp @@ -20,7 +20,6 @@ =========================================================================*/ #include "imstkCylinder.h" - #include "imstkLogger.h" namespace imstk diff --git a/Source/Geometry/Analytic/imstkCylinder.h b/Source/Geometry/Analytic/imstkCylinder.h index d3f160faec2811a05088ff2745ed927516a9af81..f3835662bb087a905ffb60fbc393ffd13627fb9e 100644 --- a/Source/Geometry/Analytic/imstkCylinder.h +++ b/Source/Geometry/Analytic/imstkCylinder.h @@ -21,7 +21,6 @@ #pragma once -// imstk #include "imstkAnalyticalGeometry.h" namespace imstk @@ -37,7 +36,16 @@ public: /// /// \brief Constructor /// - Cylinder(const std::string& name = std::string("")) : AnalyticalGeometry(Type::Cylinder, name) {} + explicit Cylinder(const Vec3d& pos = Vec3d(0.0, 0.0, 0.0), const double radius = 1.0, const double length = 1.0, + const Vec3d& orientationAxis = Vec3d(0.0, 1.0, 0.0), const std::string& name = std::string("")) : + AnalyticalGeometry(Type::Cylinder, name) + { + setPosition(pos); + setOrientationAxis(orientationAxis); + setRadius(radius); + setLength(length); + updatePostTransformData(); + } /// /// \brief Print the cylinder info @@ -72,6 +80,10 @@ public: protected: friend class VTKCylinderRenderDelegate; + // Hide these unimplemented functions + using AnalyticalGeometry::getFunctionValue; + //using AnalyticalGeometry::getFunctionGrad; + void applyScaling(const double s) override; void updatePostTransformData() const override; diff --git a/Source/Geometry/Analytic/imstkPlane.h b/Source/Geometry/Analytic/imstkPlane.h index 724913d5b638149766abd86ad4337b272480937d..13c1dad36fcc997f2374e9b729e3d21f2b9bffad 100644 --- a/Source/Geometry/Analytic/imstkPlane.h +++ b/Source/Geometry/Analytic/imstkPlane.h @@ -21,7 +21,6 @@ #pragma once -// imstk #include "imstkAnalyticalGeometry.h" namespace imstk @@ -37,7 +36,14 @@ public: /// /// \brief Constructor /// - Plane(const std::string& name = std::string("")) : AnalyticalGeometry(Type::Plane, name) {} + explicit Plane(const Vec3d& pos = Vec3d(0.0, 0.0, 0.0), const Vec3d& normal = Vec3d(0.0, 1.0, 0.0), + const std::string& name = std::string("")) : + AnalyticalGeometry(Type::Plane, name) + { + setPosition(pos); + setNormal(normal.normalized()); + updatePostTransformData(); + } /// /// \brief Print the plane info @@ -70,6 +76,16 @@ public: /// void setWidth(const double w); + /// + /// \brief Returns signed distance to surface at pos + /// + double getFunctionValue(const Vec3d& pos) const override { return m_orientationAxis.dot(pos - m_position); } + +/// +/// \brief Returns gradient of signed distance field at pos +/// +//virtual Vec3d getFunctionGrad(const Vec3d& imstkNotUsed(pos), const Vec3d& dx) const override { return dx.cwiseProduct(m_orientationAxis); } + protected: friend class VTKPlaneRenderDelegate; diff --git a/Source/Geometry/Analytic/imstkSphere.cpp b/Source/Geometry/Analytic/imstkSphere.cpp index bd99d22168af7c02251a5d112300cf7f9a176481..d9f71893380bc94756db215c3b1a1cf1fbe04161 100644 --- a/Source/Geometry/Analytic/imstkSphere.cpp +++ b/Source/Geometry/Analytic/imstkSphere.cpp @@ -20,7 +20,6 @@ =========================================================================*/ #include "imstkSphere.h" - #include "imstkLogger.h" namespace imstk @@ -32,12 +31,6 @@ Sphere::print() const LOG(INFO) << "Radius: " << m_radius; } -double -Sphere::getVolume() const -{ - return 4.0 / 3.0 * PI * m_radius * m_radius * m_radius; -} - double Sphere::getRadius(DataType type /* = DataType::PostTransform */) { @@ -81,12 +74,6 @@ Sphere::computeBoundingBox(Vec3d& lowerCorner, Vec3d& upperCorner, const double } } -void -Sphere::applyScaling(const double s) -{ - this->setRadius(m_radius * s); -} - void Sphere::updatePostTransformData() const { diff --git a/Source/Geometry/Analytic/imstkSphere.h b/Source/Geometry/Analytic/imstkSphere.h index 0ee237edea41e04b4c8c3833d95339ef9a3366dc..fad674237f7f6bc6e62c94bf0b5ae48bbc7262bf 100644 --- a/Source/Geometry/Analytic/imstkSphere.h +++ b/Source/Geometry/Analytic/imstkSphere.h @@ -21,7 +21,6 @@ #pragma once -// imstk #include "imstkAnalyticalGeometry.h" namespace imstk @@ -37,7 +36,12 @@ public: /// /// \brief Constructor /// - Sphere(const std::string& name = std::string("")) : AnalyticalGeometry(Type::Sphere, name) {} + explicit Sphere(const Vec3d& pos = Vec3d(0.0, 0.0, 0.0), const double radius = 1.0, const std::string& name = std::string("")) : + AnalyticalGeometry(Type::Sphere, name) + { + setPosition(pos); + setRadius(radius); + } /// /// \brief Print the sphere info @@ -47,7 +51,7 @@ public: /// /// \brief Returns the volume of the sphere /// - double getVolume() const override; + double getVolume() const override { return 4.0 / 3.0 * PI * m_radius * m_radius * m_radius; } /// /// \brief Returns the radius of the sphere @@ -64,10 +68,20 @@ public: /// virtual void computeBoundingBox(Vec3d& lowerCorner, Vec3d& upperCorner, const double paddingPercent = 0.0) const override; + /// + /// \brief Returns signed distance to surface given position + /// + double getFunctionValue(const Vec3d& pos) const override { return (pos - m_position).norm() - m_radius; } + +/// +/// \brief Returns analytical gradient of distances given position +/// +//Vec3d getFunctionGrad(const Vec3d& pos, const Vec3d& dx) const override { return 2.0 * (pos - m_position).cwiseProduct(dx); } + protected: friend class VTKSphereRenderDelegate; - void applyScaling(const double s) override; + void applyScaling(const double s) override { this->setRadius(m_radius * s); } void updatePostTransformData() const override; double m_radius = 1.0; ///> Radius of the sphere diff --git a/Source/Geometry/CMakeLists.txt b/Source/Geometry/CMakeLists.txt index d3eb93e9a206193c0108dc7755c6dc3b7f400c3f..08fd2950ae190bed849b024f7eb7be26193137cc 100644 --- a/Source/Geometry/CMakeLists.txt +++ b/Source/Geometry/CMakeLists.txt @@ -4,9 +4,8 @@ include(imstkAddLibrary) imstk_add_library( Geometry DEPENDS - Common - ${VTK_LIBRARIES} - ) + Common + ${VTK_LIBRARIES}) #----------------------------------------------------------------------------- # Testing diff --git a/Source/Geometry/Decal/imstkDecal.cpp b/Source/Geometry/Decal/imstkDecal.cpp index 2b0d5d09f4ffc3195ad75781670688a2427d412c..fd0167584037cc9f4e1a6d46258a0bec65df418a 100644 --- a/Source/Geometry/Decal/imstkDecal.cpp +++ b/Source/Geometry/Decal/imstkDecal.cpp @@ -21,7 +21,11 @@ #include "imstkDecal.h" #include "imstkLogger.h" -#include "imstkMath.h" + +#pragma warning( push ) +#pragma warning( disable : 4201 ) +#include <glm/gtc/matrix_transform.hpp> +#pragma warning( pop ) namespace imstk { diff --git a/Source/Geometry/Decal/imstkDecal.h b/Source/Geometry/Decal/imstkDecal.h index e8c50d5cbb2b60666a69fc79309ddf0138d5bb3b..1f789e8d155aadfca4d04cc6c0994fa6783351f8 100644 --- a/Source/Geometry/Decal/imstkDecal.h +++ b/Source/Geometry/Decal/imstkDecal.h @@ -20,13 +20,12 @@ =========================================================================*/ #pragma once + #include "imstkAnalyticalGeometry.h" #pragma warning( push ) #pragma warning( disable : 4201 ) -#include "glm/glm.hpp" -#include "glm/gtc/matrix_transform.hpp" -#include "glm/gtc/quaternion.hpp" +#include <glm/glm.hpp> #pragma warning( pop ) namespace imstk @@ -55,6 +54,10 @@ public: protected: friend class VulkanDecalRenderDelegate; + // Hide these functions + using AnalyticalGeometry::getFunctionValue; + //using AnalyticalGeometry::getFunctionGrad; + void applyScaling(const double s) override; glm::vec3 m_dimensions; diff --git a/Source/Geometry/Decal/imstkDecalPool.cpp b/Source/Geometry/Decal/imstkDecalPool.cpp index 7c496a5191b751e65620cb2d25bf53a510d43ab3..2b50adadf5d005e3a6e0c4f3fc000fa4b6ac6bdf 100644 --- a/Source/Geometry/Decal/imstkDecalPool.cpp +++ b/Source/Geometry/Decal/imstkDecalPool.cpp @@ -20,6 +20,7 @@ =========================================================================*/ #include "imstkDecalPool.h" +#include "imstkDecal.h" #include "imstkLogger.h" namespace imstk diff --git a/Source/Geometry/Decal/imstkDecalPool.h b/Source/Geometry/Decal/imstkDecalPool.h index 35c4ec5e3dd3eb4b8af5a5ae2ab2b4beb68009ef..dd317ae7d2f8f3867b5fd76cdac93a221f03f0d3 100644 --- a/Source/Geometry/Decal/imstkDecalPool.h +++ b/Source/Geometry/Decal/imstkDecalPool.h @@ -20,16 +20,19 @@ =========================================================================*/ #pragma once - -#include <queue> +#include "imstkGeometry.h" #include <array> +#include <queue> -#include "imstkDecal.h" -#include "imstkGeometry.h" -//#include "imstkRenderMaterial.h" +#pragma warning( push ) +#pragma warning( disable : 4201 ) +#include "glm/glm.hpp" +#pragma warning( pop ) namespace imstk { +class Decal; + class DecalPool : public Geometry { public: diff --git a/Source/Geometry/Implicit/imstkCompositeImplicitGeometry.cpp b/Source/Geometry/Implicit/imstkCompositeImplicitGeometry.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c9211f24b75ee5876e38a54ddae068c44a2d18ee --- /dev/null +++ b/Source/Geometry/Implicit/imstkCompositeImplicitGeometry.cpp @@ -0,0 +1,50 @@ +/*========================================================================= + + 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 "imstkCompositeImplicitGeometry.h" + +namespace imstk +{ +double +CompositeImplicitGeometry::getFunctionValue(const Vec3d& pos) const +{ + // Initialize everything to outside + double distA = std::numeric_limits<double>::max(); + for (auto i = geometries.begin(); i != geometries.end(); i++) + { + const GeometryBoolPair& pair = *i; + double distB = pair.first->getFunctionValue(pos); + switch (pair.second) + { + case GeometryBoolType::Difference: + distA = std::max(distA, -distB); + break; + case GeometryBoolType::Intersection: + distA = std::max(distA, distB); + break; + case GeometryBoolType::Union: + distA = std::min(distA, distB); + break; + } + } + return distA; +} +} \ No newline at end of file diff --git a/Source/Geometry/Implicit/imstkCompositeImplicitGeometry.h b/Source/Geometry/Implicit/imstkCompositeImplicitGeometry.h new file mode 100644 index 0000000000000000000000000000000000000000..7ebd9cc43fa16ad71e5788c8d75cdf8296ef9753 --- /dev/null +++ b/Source/Geometry/Implicit/imstkCompositeImplicitGeometry.h @@ -0,0 +1,61 @@ +/*========================================================================= + + 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 "imstkImplicitGeometry.h" + +namespace imstk +{ +/// +/// \class ImplicitGeometry +/// +/// \brief Class that can represent the geometry of multiple implicit geometries as boolean functions +/// One may supply it with multiple implicit geometries and the operation they would like +/// +class CompositeImplicitGeometry : public ImplicitGeometry +{ +public: + enum class GeometryBoolType + { + Intersection, + Difference, + Union + }; + + using GeometryBoolPair = std::pair<std::shared_ptr<ImplicitGeometry>, GeometryBoolType>; + +public: + CompositeImplicitGeometry(std::string name = "") : ImplicitGeometry(Type::CompositeImplicitGeometry, name) { } + virtual ~CompositeImplicitGeometry() override = default; + +public: + /// + /// \brief Returns signed distance to surface at pos + /// + virtual double getFunctionValue(const Vec3d& pos) const override; + + void addImplicitGeometry(std::shared_ptr<ImplicitGeometry> geometry, const GeometryBoolType type) { geometries.push_back(GeometryBoolPair(geometry, type)); } + +protected: + std::list<GeometryBoolPair> geometries; +}; +} diff --git a/Source/Geometry/Implicit/imstkImplicitFunctionFiniteDifferenceFunctor.h b/Source/Geometry/Implicit/imstkImplicitFunctionFiniteDifferenceFunctor.h new file mode 100644 index 0000000000000000000000000000000000000000..fd345ad460ca7323c2de55588ceee3c4ba469ed0 --- /dev/null +++ b/Source/Geometry/Implicit/imstkImplicitFunctionFiniteDifferenceFunctor.h @@ -0,0 +1,168 @@ +/*========================================================================= + + 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 "imstkImplicitGeometry.h" +#include "imstkSignedDistanceField.h" + +namespace imstk +{ +/// +/// \brief Base struct for gradient functors +/// +struct ImplicitFunctionGradient +{ + public: + virtual Vec3d operator()(const Vec3d& pos) const = 0; + + virtual void setDx(const Vec3d& dx) + { + this->m_dx = dx; + this->m_invDx = Vec3d(1.0 / dx[0], 1.0 / dx[1], 1.0 / dx[2]); + } + + const Vec3d& getDx() const { return m_dx; } + + void setFunction(std::shared_ptr<ImplicitGeometry> func) { this->m_func = func; } + + protected: + std::shared_ptr<ImplicitGeometry> m_func; + Vec3d m_dx = Vec3d(1.0, 1.0, 1.0); + Vec3d m_invDx = Vec3d(1.0, 1.0, 1.0); +}; + +/// +/// \brief Gradient given by central finite differences +/// +struct ImplicitFunctionCentralGradient : public ImplicitFunctionGradient +{ + public: + Vec3d operator()(const Vec3d& pos) const override + { + const ImplicitGeometry& funcRef = *m_func; + return Vec3d( + funcRef.getFunctionValue(Vec3d(pos[0] + m_dx[0], pos[1], pos[2])) - funcRef.getFunctionValue(Vec3d(pos[0] - m_dx[0], pos[1], pos[2])), + funcRef.getFunctionValue(Vec3d(pos[0], pos[1] + m_dx[1], pos[2])) - funcRef.getFunctionValue(Vec3d(pos[0], pos[1] - m_dx[1], pos[2])), + funcRef.getFunctionValue(Vec3d(pos[0], pos[1], pos[2] + m_dx[2])) - funcRef.getFunctionValue(Vec3d(pos[0], pos[1], pos[2] - m_dx[2]))).cwiseProduct(m_invDx) * 0.5; + } +}; + +/// +/// \brief Gradient given by forward finite differences +/// +struct ImplicitFunctionForwardGradient : public ImplicitFunctionGradient +{ + public: + Vec3d operator()(const Vec3d& pos) const override + { + const ImplicitGeometry& funcRef = *m_func; + const double centralValue = funcRef.getFunctionValue(Vec3d(pos[0], pos[1], pos[2])); + const double maxValueX = funcRef.getFunctionValue(Vec3d(pos[0] + m_dx[0], pos[1], pos[2])); + const double maxValueY = funcRef.getFunctionValue(Vec3d(pos[0], pos[1] + m_dx[1], pos[2])); + const double maxValueZ = funcRef.getFunctionValue(Vec3d(pos[0], pos[1], pos[2] + m_dx[2])); + return Vec3d( + maxValueX - centralValue, + maxValueY - centralValue, + maxValueZ - centralValue).cwiseProduct(m_invDx); + } +}; + +/// +/// \brief Gradient given by backward finite differences +/// +struct ImplicitFunctionBackwardGradient : public ImplicitFunctionGradient +{ + public: + Vec3d operator()(const Vec3d& pos) const override + { + const ImplicitGeometry& funcRef = *m_func; + const double centralValue = funcRef.getFunctionValue(Vec3d(pos[0], pos[1], pos[2])); + const double minValueX = funcRef.getFunctionValue(Vec3d(pos[0] - m_dx[0], pos[1], pos[2])); + const double minValueY = funcRef.getFunctionValue(Vec3d(pos[0], pos[1] - m_dx[1], pos[2])); + const double minValueZ = funcRef.getFunctionValue(Vec3d(pos[0], pos[1], pos[2] - m_dx[2])); + return Vec3d( + centralValue - minValueX, + centralValue - minValueY, + centralValue - minValueZ).cwiseProduct(m_invDx); + } +}; + +/// +/// \brief Gradient given by forward finite differences +/// +struct StructuredForwardGradient : public ImplicitFunctionGradient +{ + public: + Vec3d operator()(const Vec3d& pos) const override + { + const SignedDistanceField& funcRef = *static_cast<SignedDistanceField*>(m_func.get()); + const double centralValue = funcRef.getFunctionValueCoord(Vec3i(static_cast<int>(pos[0]), static_cast<int>(pos[1]), static_cast<int>(pos[2]))); + const double maxValueX = funcRef.getFunctionValueCoord(Vec3i(static_cast<int>(pos[0] + m_dxi[0]), static_cast<int>(pos[1]), static_cast<int>(pos[2]))); + const double maxValueY = funcRef.getFunctionValueCoord(Vec3i(static_cast<int>(pos[0]), static_cast<int>(pos[1] + m_dxi[1]), static_cast<int>(pos[2]))); + const double maxValueZ = funcRef.getFunctionValueCoord(Vec3i(static_cast<int>(pos[0]), static_cast<int>(pos[1]), static_cast<int>(pos[2] + m_dxi[2]))); + return Vec3d( + maxValueX - centralValue, + maxValueY - centralValue, + maxValueZ - centralValue).cwiseProduct(m_invDx); + } + + void setDx(const Vec3i& dx, const Vec3d& dxs) + { + m_dxi = dx; + ImplicitFunctionGradient::setDx(dxs.cwiseProduct(m_dxi.cast<double>())); + } + + protected: + using ImplicitFunctionGradient::setDx; + Vec3i m_dxi; +}; + +/// +/// \brief Gradient given by backward finite differences +/// +struct StructuredBackwardGradient : public ImplicitFunctionGradient +{ + public: + Vec3d operator()(const Vec3d& pos) const override + { + const SignedDistanceField& funcRef = *static_cast<SignedDistanceField*>(m_func.get()); + const double centralValue = funcRef.getFunctionValueCoord(Vec3i(static_cast<int>(pos[0]), static_cast<int>(pos[1]), static_cast<int>(pos[2]))); + const double minValueX = funcRef.getFunctionValueCoord(Vec3i(static_cast<int>(pos[0] - m_dxi[0]), static_cast<int>(pos[1]), static_cast<int>(pos[2]))); + const double minValueY = funcRef.getFunctionValueCoord(Vec3i(static_cast<int>(pos[0]), static_cast<int>(pos[1] - m_dxi[1]), static_cast<int>(pos[2]))); + const double minValueZ = funcRef.getFunctionValueCoord(Vec3i(static_cast<int>(pos[0]), static_cast<int>(pos[1]), static_cast<int>(pos[2] - m_dxi[2]))); + return Vec3d( + centralValue - minValueX, + centralValue - minValueY, + centralValue - minValueZ).cwiseProduct(m_invDx); + } + + void setDx(const Vec3i& dx, const Vec3d& dxs) + { + m_dxi = dx; + ImplicitFunctionGradient::setDx(dxs); + } + + protected: + using ImplicitFunctionGradient::setDx; + Vec3i m_dxi; +}; +} \ No newline at end of file diff --git a/Source/Controllers/imstkSceneObjectControllerBase.h b/Source/Geometry/Implicit/imstkImplicitGeometry.h similarity index 61% rename from Source/Controllers/imstkSceneObjectControllerBase.h rename to Source/Geometry/Implicit/imstkImplicitGeometry.h index fb590c6340ad916149850e32f47242ff66c8ce11..808edc58932fa149274a3bd2fc2fc3f173ea685c 100644 --- a/Source/Controllers/imstkSceneObjectControllerBase.h +++ b/Source/Geometry/Implicit/imstkImplicitGeometry.h @@ -21,35 +21,28 @@ #pragma once +#include "imstkGeometry.h" + namespace imstk { /// -/// \class SceneObjectControllerBase +/// \class ImplicitGeometry /// -/// \brief Base class for all the scene object controllers +/// \brief Defines implicit geometry with an implicit function +/// Implicit functions must be decoupled from geometry /// -class SceneObjectControllerBase +class ImplicitGeometry : public Geometry { public: - /// - /// \brief Constructor/Destructor - /// - SceneObjectControllerBase() = default; - ~SceneObjectControllerBase() = default; + virtual ~ImplicitGeometry() override = default; - /// - /// \brief Update controlled scene objects using latest tracking information - /// - virtual void updateControlledObjects() = 0; - - /// - /// \brief Apply forces to the haptic device - /// - virtual void applyForces() = 0; +protected: + ImplicitGeometry(Type geomType, std::string name = "") : Geometry(geomType, name) { } +public: /// - /// \brief + /// \brief Returns function value given position /// - virtual void setTrackerToOutOfDate() = 0; + virtual double getFunctionValue(const Vec3d& pos) const = 0; }; -} // imstk +} diff --git a/Source/Geometry/Implicit/imstkSignedDistanceField.cpp b/Source/Geometry/Implicit/imstkSignedDistanceField.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bda126dc518a3687eb082e9ba46628e0746331ad --- /dev/null +++ b/Source/Geometry/Implicit/imstkSignedDistanceField.cpp @@ -0,0 +1,114 @@ +/*========================================================================= + + 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 "imstkSignedDistanceField.h" +#include "imstkDataArray.h" +#include "imstkImageData.h" +#include "imstkLogger.h" + +namespace imstk +{ +/// +/// \brief Accepts structured coordinates (ie: pre int cast, [0, dim)) so it can do interpolation +/// origin should be image origin + spacing/2 +/// +template<typename T> +static T +trilinearSample(const Vec3d& structuredPt, T* imgPtr, const Vec3i& dim, const int numComps, const int comp) +{ + // minima of voxel, clamped to bounds + const Vec3i s1 = structuredPt.cast<int>().cwiseMax(0).cwiseMin(dim - Vec3i(1, 1, 1)); + + // maxima of voxel, clamped to bounds + const Vec3i s2 = (structuredPt.cast<int>() + Vec3i(1, 1, 1)).cwiseMax(0).cwiseMin(dim - Vec3i(1, 1, 1)); + + const size_t index000 = ImageData::getScalarIndex(s1.x(), s1.y(), s1.z(), dim, numComps) + comp; + const size_t index100 = ImageData::getScalarIndex(s2.x(), s1.y(), s1.z(), dim, numComps) + comp; + const size_t index110 = ImageData::getScalarIndex(s2.x(), s2.y(), s1.z(), dim, numComps) + comp; + const size_t index010 = ImageData::getScalarIndex(s1.x(), s2.y(), s1.z(), dim, numComps) + comp; + const size_t index001 = ImageData::getScalarIndex(s1.x(), s1.y(), s2.z(), dim, numComps) + comp; + const size_t index101 = ImageData::getScalarIndex(s2.x(), s1.y(), s2.z(), dim, numComps) + comp; + const size_t index111 = ImageData::getScalarIndex(s2.x(), s2.y(), s2.z(), dim, numComps) + comp; + const size_t index011 = ImageData::getScalarIndex(s1.x(), s2.y(), s2.z(), dim, numComps) + comp; + + const double val000 = static_cast<double>(imgPtr[index000]); + const double val100 = static_cast<double>(imgPtr[index100]); + const double val110 = static_cast<double>(imgPtr[index110]); + const double val010 = static_cast<double>(imgPtr[index010]); + + const double val001 = static_cast<double>(imgPtr[index001]); + const double val101 = static_cast<double>(imgPtr[index101]); + const double val111 = static_cast<double>(imgPtr[index111]); + const double val011 = static_cast<double>(imgPtr[index011]); + + // Interpolants + //const Vec3d t = s2.cast<double>() - structuredPt; + const Vec3d t = structuredPt - s2.cast<double>(); + + // Interpolate along x + const double ax = val000 + (val100 - val000) * t[0]; + const double bx = val010 + (val110 - val010) * t[0]; + + const double dx = val001 + (val101 - val001) * t[0]; + const double ex = val011 + (val111 - val011) * t[0]; + + // Interpolate along y + const double cy = ax + (bx - ax) * t[1]; + const double fy = dx + (ex - dx) * t[1]; + + // Interpolate along z + const double gz = cy + (fy - cy) * t[2]; + + return static_cast<T>(gz); +} + +SignedDistanceField::SignedDistanceField(std::shared_ptr<ImageData> imageData, std::string name) : + ImplicitGeometry(Type::SignedDistanceField, name), + m_imageDataSdf(imageData) +{ + m_invSpacing = m_imageDataSdf->getInvSpacing(); + m_bounds = m_imageDataSdf->getBounds(); + m_shift = m_imageDataSdf->getOrigin() - m_imageDataSdf->getSpacing() * 0.5; + + if (m_imageDataSdf->getScalarType() != IMSTK_DOUBLE) + { + LOG(WARNING) << "SignedDistanceField requires double input image"; + return; + } + + m_scalars = std::dynamic_pointer_cast<DataArray<double>>(m_imageDataSdf->getScalars()); +} + +double +SignedDistanceField::getFunctionValue(const Vec3d& pos) const +{ + // origin at center of first voxel + const Vec3d structuredPt = (pos - m_shift).cwiseProduct(m_invSpacing); + return trilinearSample(structuredPt, m_scalars->getPointer(), m_imageDataSdf->getDimensions(), 1, 0); +} + +double +SignedDistanceField::getFunctionValueCoord(const Vec3i& coord) const +{ + const Vec3i clampedCoord = coord.cwiseMin(m_imageDataSdf->getDimensions() - Vec3i(1, 1, 1)).cwiseMax(0); + return (*m_scalars)[m_imageDataSdf->getScalarIndex(clampedCoord)]; +} +} \ No newline at end of file diff --git a/Source/Geometry/Implicit/imstkSignedDistanceField.h b/Source/Geometry/Implicit/imstkSignedDistanceField.h new file mode 100644 index 0000000000000000000000000000000000000000..6a52e200e905821f3ffb6ea6faf899b6937dd029 --- /dev/null +++ b/Source/Geometry/Implicit/imstkSignedDistanceField.h @@ -0,0 +1,75 @@ +/*========================================================================= + + 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 "imstkImplicitGeometry.h" + +namespace imstk +{ +class ImageData; +template<typename T> class DataArray; + +/// +/// \class SignedDistanceField +/// +/// \brief Structured field of signed distances implemented with ImageData +/// +class SignedDistanceField : public ImplicitGeometry +{ +public: + /// + /// \brief Initialize with an image data SDF + /// + SignedDistanceField(std::shared_ptr<ImageData> imageData, std::string name = ""); + virtual ~SignedDistanceField() override = default; + +public: + /// + /// \brief Returns signed distance to surface at pos, returns clamped/nearest if out of bounds + /// + double getFunctionValue(const Vec3d& pos) const override; + + /// + /// \brief Returns signed distance to surface at coordinate + /// + double getFunctionValueCoord(const Vec3i& coord) const; + + /// + /// \brief Returns the bounds of the field + /// + const Vec6d& getBounds() const { return m_bounds; } + + /// + /// \brief Get the SDF as a float image + /// + std::shared_ptr<ImageData> getImage() const { return m_imageDataSdf; } + +protected: + std::shared_ptr<ImageData> m_imageDataSdf; + + Vec3d m_invSpacing; + Vec6d m_bounds; + Vec3d m_shift; + + std::shared_ptr<DataArray<double>> m_scalars; +}; +} \ No newline at end of file diff --git a/Source/Geometry/Mesh/imstkHexahedralMesh.cpp b/Source/Geometry/Mesh/imstkHexahedralMesh.cpp index 42666b8e3a18d11e4bad6afebf2aabc15fa773ab..5e373edb5b0c21b5816e046f26d49b314032db06 100644 --- a/Source/Geometry/Mesh/imstkHexahedralMesh.cpp +++ b/Source/Geometry/Mesh/imstkHexahedralMesh.cpp @@ -23,8 +23,6 @@ #include "imstkSurfaceMesh.h" #include "imstkLogger.h" -#include <array> - namespace imstk { void diff --git a/Source/Geometry/Mesh/imstkImageData.cpp b/Source/Geometry/Mesh/imstkImageData.cpp index 9e286d43266ac385bedcd5b5a108036c693cb832..851a2cc971e61a790f358c7bc271b134c1be7c0f 100644 --- a/Source/Geometry/Mesh/imstkImageData.cpp +++ b/Source/Geometry/Mesh/imstkImageData.cpp @@ -20,123 +20,167 @@ =========================================================================*/ #include "imstkImageData.h" - -// vtk -#include "vtkImageReslice.h" -#include "vtkTransform.h" -#include <vtkImageData.h> +#include "imstkLogger.h" +#include "imstkDataArray.h" namespace imstk { +template<typename FROM_TYPE, typename TO_TYPE> +static void +castArray(std::shared_ptr<DataArray<FROM_TYPE>> fromArray, std::shared_ptr<DataArray<TO_TYPE>> toArray) +{ + const DataArray<FROM_TYPE>& fromArrayRef = *fromArray; + DataArray<TO_TYPE>& toArrayRef = *toArray; + const size_t numVals = fromArray->size(); + for (size_t i = 0; i < numVals; i++) + { + toArrayRef[i] = static_cast<TO_TYPE>(fromArrayRef[i]); + } +} + +template<typename FROM_TYPE> +static void +castImage(std::shared_ptr<AbstractDataArray> fromScalars, std::shared_ptr<ImageData> toImage) +{ + const ScalarType toType = toImage->getScalars()->getScalarType(); + switch (toType) + { + TemplateMacro(castArray( + std::dynamic_pointer_cast<DataArray<FROM_TYPE>>(fromScalars), + std::dynamic_pointer_cast<DataArray<IMSTK_TT>>(toImage->getScalars())); ); + default: + LOG(WARNING) << "Unknown scalar type"; + break; + } + ; +} + ImageData::ImageData(const std::string& name) : PointSet(Geometry::Type::ImageData, name), - m_dataTransform(vtkSmartPointer<vtkTransform>::New()) + m_scalarArray(nullptr) { } void ImageData::print() const { - Geometry::print(); + PointSet::print(); + LOG(INFO) << "Scalar Type: " << static_cast<int>(m_scalarArray->getScalarType()); + LOG(INFO) << "Number of Components" << m_numComps; + LOG(INFO) << "Dimensions: " << m_dims[0] << ", " << m_dims[1] << ", " << m_dims[2]; + LOG(INFO) << "Spacing: " << m_spacing[0] << ", " << m_spacing[1] << ", " << m_spacing[2]; + LOG(INFO) << "Origin: " << m_origin[0] << ", " << m_origin[1] << ", " << m_origin[2]; + LOG(INFO) << "Bounds: "; + LOG(INFO) << "\t" << m_bounds[0] << ", " << m_bounds[1]; + LOG(INFO) << "\t" << m_bounds[2] << ", " << m_bounds[3]; + LOG(INFO) << "\t" << m_bounds[4] << ", " << m_bounds[5]; } double ImageData::getVolume() const { - if (!this->m_data) + if (m_scalarArray == nullptr) { return 0.0; } - double bounds[6]; - this->m_data->GetBounds(bounds); - return ((bounds[1] - bounds[0]) * - (bounds[3] - bounds[2]) * - (bounds[5] - bounds[4])); + return (m_dims[0] * m_spacing.x()) * + (m_dims[1] * m_spacing.y()) * + (m_dims[2] * m_spacing.z()); } -void -ImageData::initialize(vtkImageData* im) +void* +ImageData::getVoidPointer() { - this->clear(); - if (im) - { - this->m_data = vtkSmartPointer<vtkImageData>::New(); - this->m_data->DeepCopy(im); - } + return m_scalarArray->getVoidPointer(); } -void -ImageData::clear() +std::shared_ptr<ImageData> +ImageData::cast(ScalarType toType) { - if (this->m_data) + // Create image of new type + std::shared_ptr<ImageData> results = std::make_shared<ImageData>(); + results->allocate(toType, m_numComps, m_dims, m_spacing, m_origin); + switch (m_scalarArray->getScalarType()) { - this->m_data = nullptr; + TemplateMacro(castImage<IMSTK_TT>(m_scalarArray, results); ); + default: + LOG(WARNING) << "Unknown scalar type"; + break; } - this->m_dataTransform->Identity(); - this->m_transformApplied = true; - this->m_dataModified = true; + ; + return results; } -vtkImageData* -ImageData::getData(DataType type) +const ScalarType +ImageData::getScalarType() const { - if (type == DataType::PostTransform) - { - this->updatePostTransformData(); - } - return this->m_data; + return m_scalarArray->getScalarType(); } void -ImageData::applyTranslation(const Vec3d t) +ImageData::setScalars(std::shared_ptr<AbstractDataArray> scalars, const int numComps, int* dim) { - this->m_dataTransform->Translate(t[0], t[1], t[2]); - - this->m_dataModified = true; - this->m_transformApplied = false; + CHECK(scalars != nullptr); + if (dim[0] * dim[1] * dim[2] * numComps != scalars->size()) + { + LOG(WARNING) << "Scalars don't align"; + } + m_scalarArray = scalars; + m_dims[0] = dim[0]; + m_dims[1] = dim[1]; + m_dims[2] = dim[2]; + m_numComps = numComps; } void -ImageData::applyScaling(const double s) +ImageData::allocate(const ScalarType type, const int numComps, const Vec3i& dims, const Vec3d& spacing, const Vec3d& origin) { - this->m_dataTransform->Scale(s, s, s); - - this->m_dataModified = true; - this->m_transformApplied = false; + m_dims = dims; + m_origin = origin; + setSpacing(spacing); + m_numComps = numComps; + const size_t numVals = static_cast<size_t>(dims[0] * dims[1] * dims[2] * numComps); + switch (type) + { + TemplateMacro(m_scalarArray = std::make_shared<DataArray<IMSTK_TT>>(numVals); ); + default: + LOG(WARNING) << "Tried to allocate unknown scalar type"; + break; + } + // When allocation is done, post modified on the image + connect<Event>(m_scalarArray, EventType::Modified, [&](Event*) { this->postEvent(Event(EventType::Modified)); }); } void -ImageData::applyRotation(const Mat3d r) +ImageData::computePoints() { - vtkNew<vtkMatrix4x4> mat; - for (int i = 0; i < 3; ++i) + StdVectorOfVec3d vertices(m_dims[0] * m_dims[1] * m_dims[2]); + const Vec3d shift = m_origin + m_spacing * 0.5; + int i = 0; + for (int z = 0; z < m_dims[2]; z++) { - for (int j = 0; j < 3; ++j) + for (int y = 0; y < m_dims[1]; y++) { - mat->SetElement(i, j, r(i, j)); + for (int x = 0; x < m_dims[0]; x++, i++) + { + vertices[i] = Vec3d(x, y, z).cwiseProduct(m_spacing) + shift; + } } } - this->m_dataTransform->Concatenate(mat); - - this->m_dataModified = true; - this->m_transformApplied = false; + setInitialVertexPositions(vertices); + setVertexPositions(vertices); } void -ImageData::updatePostTransformData() const +ImageData::clear() { - if (m_transformApplied || !this->m_data) + if (this->m_scalarArray != nullptr) { - return; + this->m_scalarArray = nullptr; } - - vtkNew<vtkImageReslice> reslice; - reslice->SetInputData(this->m_data); - reslice->SetResliceTransform(this->m_dataTransform); - reslice->SetInterpolationModeToLinear(); - reslice->Update(); - this->m_data->DeepCopy(reslice->GetOutput()); + //this->m_dataTransform->Identity(); this->m_transformApplied = true; + this->m_dataModified = true; } } // imstk diff --git a/Source/Geometry/Mesh/imstkImageData.h b/Source/Geometry/Mesh/imstkImageData.h index 2ac99e47d4ce38a6d2518db962cf959d4f96bf0d..7ef38853a26098235fb61d8acdb83e1f39e36d2d 100644 --- a/Source/Geometry/Mesh/imstkImageData.h +++ b/Source/Geometry/Mesh/imstkImageData.h @@ -21,23 +21,17 @@ #pragma once -// imstk #include "imstkPointSet.h" - -// vtk -#include "vtkSmartPointer.h" - -// forward declarations -class vtkTransform; -class vtkImageData; -class vtkTransform; +#include "imstkTypes.h" namespace imstk { +class AbstractDataArray; + /// /// \class ImageData /// -/// \brief Class to represent 2D and 3D image data (i.e. structured points) +/// \brief Class to represent 1, 2, or 3D image data (i.e. structured points) /// class ImageData : public PointSet { @@ -47,6 +41,12 @@ public: /// ImageData(const std::string& name = std::string("")); + /// + /// \brief Destructor + /// + virtual ~ImageData() override = default; + +public: /// /// \brief Print the image data info /// @@ -58,32 +58,122 @@ public: double getVolume() const override; /// - /// \brief Initialize to an existing image data + /// \brief Returns the dimensions of the image /// - void initialize(vtkImageData* im); + const Vec3i& getDimensions() const { return m_dims; } /// - /// \brief Clear the data + /// \brief Returns the number of components of the image /// - void clear() override; + int getNumComponents() const { return m_numComps; } /// - /// \brief Return the underlying data + /// \brief Returns a pointer to the underlying storage of the image /// - vtkImageData* getData(DataType type = DataType::PostTransform); + void* getVoidPointer(); -protected: - friend class VTKImageDataRenderDelegate; + /// + /// \brief Returns index of data in scalar array given structured image coordinate, does no bounds checking + /// + inline size_t getScalarIndex(int x, int y, int z = 0) { return getScalarIndex(x, y, z, m_dims, m_numComps); } + inline size_t getScalarIndex(const Vec3i& imgCoord) { return getScalarIndex(imgCoord[0], imgCoord[1], imgCoord[2], m_dims, m_numComps); } + + /// + /// \brief Returns index of data in scalar array given structured image coordinate, dimensions, and number of components + /// does no bounds checking + /// + inline static size_t getScalarIndex(int x, int y, int z, const Vec3i& dims, int numComps) { return (x + dims[0] * (y + z * dims[1])) * numComps; } + + std::shared_ptr<ImageData> cast(ScalarType type); + + /// + /// \brief Returns the origin of the image + /// + const Vec3d& getOrigin() const { return m_origin; } + + /// + /// \brief Returns the spacing of the image + /// + const Vec3d& getSpacing() const { return m_spacing; } + + /// + /// \brief Returns inv spacing of the image + /// + const Vec3d& getInvSpacing() const { return m_invSpacing; } + + /// + /// \brief Returns the scalar type of the image + /// + const ScalarType getScalarType() const; + + /// + /// \brief Returns bounds of the image (voxel to voxel) + /// + const Vec6d& getBounds() + { + const Vec3d size = Vec3d( + m_spacing.x() * m_dims[0], + m_spacing.y() * m_dims[1], + m_spacing.z() * m_dims[2]); + + m_bounds[0] = m_origin.x(); + m_bounds[1] = m_origin.x() + size.x(); + m_bounds[2] = m_origin.y(); + m_bounds[3] = m_origin.y() + size.y(); + m_bounds[4] = m_origin.z(); + m_bounds[5] = m_origin.z() + size.z(); + + return m_bounds; + } + + /// + /// \brief Returns point data scalars + /// + std::shared_ptr<AbstractDataArray> getScalars() const { return m_scalarArray; } - vtkSmartPointer<vtkImageData> m_data; ///> ImageData - vtkSmartPointer<vtkTransform> m_dataTransform; + /// + /// \brief Sets the scalars + /// + void setScalars(std::shared_ptr<AbstractDataArray> scalars, const int numComps, int* dim); - void applyTranslation(const Vec3d t) override; + /// + /// \brief Sets the origin of the image + /// + void setOrigin(const Vec3d& origin) { m_origin = origin; } - void applyRotation(const Mat3d r) override; + /// + /// \brief Sets the spacing between pixels/voxels of the image + /// + void setSpacing(const Vec3d& spacing) + { + m_spacing = spacing; + m_invSpacing = Vec3d(1.0 / spacing[0], 1.0 / spacing[1], 1.0 / spacing[2]); + } - void applyScaling(const double s) override; + /// + /// \brief Allocate image by type + /// + void allocate(const ScalarType type, const int numComps, const Vec3i& dims, const Vec3d& spacing = Vec3d(1.0, 1.0, 1.0), const Vec3d& origin = Vec3d(0.0, 0.0, 0.0)); + + /// + /// \brief Generates points in the geometry from the ImageData (center of each voxel) + /// + void computePoints(); + + /// + /// \brief Clear the data + /// + void clear() override; + +protected: + friend class VTKImageDataRenderDelegate; - void updatePostTransformData() const override; + std::shared_ptr<AbstractDataArray> m_scalarArray = nullptr; + Vec3i m_dims = Vec3i(0, 0, 0); + int m_numComps = 1; + Vec3d m_origin = Vec3d(0.0, 0.0, 0.0); + Vec3d m_spacing = Vec3d(1.0, 1.0, 1.0); + Vec3d m_invSpacing = Vec3d(1.0, 1.0, 1.0); + Vec6d m_bounds; }; } // imstk diff --git a/Source/Geometry/Mesh/imstkLineMesh.h b/Source/Geometry/Mesh/imstkLineMesh.h index 00e472e62b0dd4171deae1e5475836e34a45fd58..ed17cbb2d5b58cd2d80e3562d7a69b9722a56929 100644 --- a/Source/Geometry/Mesh/imstkLineMesh.h +++ b/Source/Geometry/Mesh/imstkLineMesh.h @@ -21,9 +21,8 @@ #pragma once -#include <array> - #include "imstkPointSet.h" +#include <array> namespace imstk { diff --git a/Source/Geometry/Mesh/imstkPointSet.cpp b/Source/Geometry/Mesh/imstkPointSet.cpp index 4f0bd8530460c6a091f1d8e928bf34934dd6be10..ede30ae3359862e1491da97e73ec8b813d7337c9 100644 --- a/Source/Geometry/Mesh/imstkPointSet.cpp +++ b/Source/Geometry/Mesh/imstkPointSet.cpp @@ -218,6 +218,18 @@ PointSet::getPointDataArray(const std::string& arrayName) const return &(it->second); } +StdVectorOfVectorf* +PointSet::getPointDataArray(const std::string& arrayName) +{ + auto it = m_pointDataMap.find(arrayName); + if (it == m_pointDataMap.end()) + { + LOG(WARNING) << "No array with such name holds any point data."; + return nullptr; + } + return &(it->second); +} + bool PointSet::hasPointDataArray(const std::string& arrayName) const { diff --git a/Source/Geometry/Mesh/imstkPointSet.h b/Source/Geometry/Mesh/imstkPointSet.h index 79c6e4b320edea8a309c6c826702a5e6b22a486d..91387a27afe3f9ae8b07898cfaf8744652afd87a 100644 --- a/Source/Geometry/Mesh/imstkPointSet.h +++ b/Source/Geometry/Mesh/imstkPointSet.h @@ -138,6 +138,11 @@ public: /// const StdVectorOfVectorf* getPointDataArray(const std::string& arrayName) const; + /// + /// \brief Get a specific data array. If the array name cannot be found, nullptr is returned. + /// + StdVectorOfVectorf* getPointDataArray(const std::string& arrayName); + /// /// \brief Check if a specific data array exists. /// diff --git a/Source/Geometry/Mesh/imstkSurfaceMesh.cpp b/Source/Geometry/Mesh/imstkSurfaceMesh.cpp index b3063fb8004b5e854e3f2a83b8b34c65afc080b9..1a8e10273a2bfbf20a05d174669989afb9f9a1ac 100644 --- a/Source/Geometry/Mesh/imstkSurfaceMesh.cpp +++ b/Source/Geometry/Mesh/imstkSurfaceMesh.cpp @@ -22,8 +22,7 @@ #include "imstkSurfaceMesh.h" #include "imstkTimer.h" #include "imstkParallelUtils.h" - -//#include "imstkGraph.h" +#include "imstkLogger.h" namespace imstk { @@ -83,9 +82,9 @@ SurfaceMesh::print() const double SurfaceMesh::getVolume() const { - // TODO - // 1. Check for water tightness - // 2. Compute volume based on signed distance + /// \todo: + /// 1. Check for water tightness + /// 2. Compute volume based on signed distance LOG(WARNING) << "SurfaceMesh::getVolume error: not implemented."; return 0.0; @@ -150,7 +149,8 @@ SurfaceMesh::computeTrianglesNormals() m_triangleNormals.at(triangleId) = ((p1 - p0).cross(p2 - p0)).normalized(); } - bool hasUVs = this->hasPointDataArray(m_defaultTCoords); + // TCoords must be named (or else it will pick up any array without a name) + bool hasUVs = m_defaultTCoords == "" ? false : this->hasPointDataArray(m_defaultTCoords); const StdVectorOfVectorf* UVs = nullptr; if (hasUVs) @@ -207,12 +207,13 @@ SurfaceMesh::computeVertexNormals() // Correct for UV seams Vec3d normal, tangent; - bool hasUVs = this->hasPointDataArray(m_defaultTCoords); + // TCoords must be named (or else it will pick up any array without a name) + bool hasUVs = m_defaultTCoords == "" ? false : this->hasPointDataArray(m_defaultTCoords); - if (hasUVs) + /*if (hasUVs) { auto UVs = this->getPointDataArray(m_defaultTCoords); - } + }*/ for (size_t vertexId = 0; vertexId < m_vertexNormals.size(); ++vertexId) { @@ -598,8 +599,8 @@ void SurfaceMesh::setLoadFactor(double loadFactor) { m_loadFactor = loadFactor; - m_maxNumVertices = (size_t)(m_originalNumVertices * m_loadFactor); - m_maxNumTriangles = (size_t)(m_originalNumTriangles * m_loadFactor); + m_maxNumVertices = static_cast<size_t>(m_originalNumVertices * m_loadFactor); + m_maxNumTriangles = static_cast<size_t>(m_originalNumTriangles * m_loadFactor); m_trianglesVertices.reserve(m_maxNumTriangles); m_vertexNormals.reserve(m_maxNumVertices); m_vertexTangents.reserve(m_maxNumVertices); @@ -631,9 +632,43 @@ SurfaceMesh::directionalScale(double s_x, double s_y, double s_z) m_initialVertexPositions[i].y() = s_y * m_initialVertexPositions[i].y(); m_vertexPositions[i].z() = s_z * m_vertexPositions[i].z(); m_initialVertexPositions[i].z() = s_z * m_initialVertexPositions[i].z(); - }); - m_dataModified = true; + }); + m_dataModified = true; m_transformApplied = false; } } + +SurfaceMesh::deepCopy(std::shared_ptr<SurfaceMesh> srcMesh) +{ + this->m_trianglesVertices = srcMesh->m_trianglesVertices; + this->m_vertexNeighborTriangles = srcMesh->m_vertexNeighborTriangles; + this->m_vertexNeighborVertices = srcMesh->m_vertexNeighborVertices; + this->m_triangleNormals = srcMesh->m_triangleNormals; + this->m_triangleTangents = srcMesh->m_triangleTangents; + this->m_vertexNormals = srcMesh->m_vertexNormals; + this->m_vertexTangents = srcMesh->m_vertexTangents; + this->m_UVSeamVertexGroups = srcMesh->m_UVSeamVertexGroups; + this->m_defaultTCoords = srcMesh->m_defaultTCoords; + this->m_originalNumTriangles = srcMesh->m_originalNumTriangles; + this->m_maxNumTriangles = srcMesh->m_maxNumTriangles; + + this->m_initialVertexPositions = srcMesh->m_initialVertexPositions; + this->m_vertexPositions = srcMesh->m_vertexPositions; + this->m_vertexPositionsPostTransform = srcMesh->m_vertexPositionsPostTransform; + this->m_pointDataMap = srcMesh->m_pointDataMap; + this->m_topologyChanged = srcMesh->m_topologyChanged; + this->m_loadFactor = srcMesh->m_loadFactor; + this->m_maxNumVertices = srcMesh->m_maxNumVertices; + this->m_originalNumVertices = srcMesh->m_originalNumVertices; + + this->m_type = srcMesh->m_type; + this->m_name = srcMesh->m_name; + this->m_geometryIndex = srcMesh->m_geometryIndex; + this->m_dataModified = srcMesh->m_dataModified; + this->m_transformModified = srcMesh->m_transformModified; + this->m_transformApplied = srcMesh->m_transformApplied; + this->m_transform = srcMesh->m_transform; + this->m_scaling = srcMesh->m_scaling; +} + } // namespace imstk diff --git a/Source/Geometry/Mesh/imstkSurfaceMesh.h b/Source/Geometry/Mesh/imstkSurfaceMesh.h index b6bc85b9a26161a64fb0554fd6a218840b55b33c..68fa61e4f742ba4fa3fdb318e5dfe4aa5c969fc1 100644 --- a/Source/Geometry/Mesh/imstkSurfaceMesh.h +++ b/Source/Geometry/Mesh/imstkSurfaceMesh.h @@ -20,14 +20,10 @@ =========================================================================*/ #pragma once - -// std library +#include "imstkPointSet.h" #include <array> #include <set> -// imstk -#include "imstkPointSet.h" - namespace imstk { /// @@ -218,9 +214,13 @@ public: void directionalScale(const double s_x, const double s_y, const double s_z); protected: - friend class VTKSurfaceMeshRenderDelegate; + /// \brief Copy the contents of one SurfaceMesh to the other + /// \todo: generalize base classes and implement for every geometry + /// + void deepCopy(std::shared_ptr<SurfaceMesh> srcMesh); + /// /// \brief Get vertex normals /// diff --git a/Source/Geometry/Mesh/imstkTetrahedralMesh.cpp b/Source/Geometry/Mesh/imstkTetrahedralMesh.cpp index 28ec30178c8d9e6a291a97588b53ef8cdd1ae4b2..5903707283663dbe86f7dec0cde8f92101b70881 100644 --- a/Source/Geometry/Mesh/imstkTetrahedralMesh.cpp +++ b/Source/Geometry/Mesh/imstkTetrahedralMesh.cpp @@ -21,7 +21,6 @@ #include "imstkTetrahedralMesh.h" #include "imstkSurfaceMesh.h" -#include "imstkSurfaceMesh.h" #include "imstkLogger.h" namespace imstk diff --git a/Source/Geometry/Mesh/imstkVolumetricMesh.cpp b/Source/Geometry/Mesh/imstkVolumetricMesh.cpp index c05f409b2a3975b615d12c9f014bfe6e2ffa4a02..163a29305ec95a0533992378bd313a2c08c1d339 100644 --- a/Source/Geometry/Mesh/imstkVolumetricMesh.cpp +++ b/Source/Geometry/Mesh/imstkVolumetricMesh.cpp @@ -20,7 +20,6 @@ =========================================================================*/ #include "imstkVolumetricMesh.h" -#include "imstkSurfaceMesh.h" #include "imstkLogger.h" namespace imstk diff --git a/Source/Geometry/Mesh/imstkVolumetricMesh.h b/Source/Geometry/Mesh/imstkVolumetricMesh.h index 6b383f7cf1d8d49cd6fe69519998079c1f8cdda6..7ad12819c363af8ff59467fb2f13bedbc10d5d15 100644 --- a/Source/Geometry/Mesh/imstkVolumetricMesh.h +++ b/Source/Geometry/Mesh/imstkVolumetricMesh.h @@ -22,7 +22,6 @@ #pragma once #include "imstkPointSet.h" - #include <memory> namespace imstk diff --git a/Source/Geometry/Particles/imstkRenderParticles.cpp b/Source/Geometry/Particles/imstkRenderParticles.cpp index 44940b52bbbe5aed0349a1b7f2e240b6151ec96d..91abd01cfb15b61d36c6840114ff2808fee572c3 100644 --- a/Source/Geometry/Particles/imstkRenderParticles.cpp +++ b/Source/Geometry/Particles/imstkRenderParticles.cpp @@ -20,7 +20,7 @@ =========================================================================*/ #include "imstkRenderParticles.h" -#include "imstkTimer.h" +#include "imstkLogger.h" namespace imstk { @@ -93,19 +93,19 @@ RenderParticles::getMaxNumParticles() } void -RenderParticles::applyTranslation(const Vec3d t) +RenderParticles::applyTranslation(const Vec3d imstkNotUsed(t)) { LOG(WARNING) << "applyTranslation Not implemented!"; } void -RenderParticles::applyRotation(const Mat3d r) +RenderParticles::applyRotation(const Mat3d imstkNotUsed(r)) { LOG(WARNING) << "applyRotation Not implemented!"; } void -RenderParticles::applyScaling(const double s) +RenderParticles::applyScaling(const double imstkNotUsed(s)) { LOG(WARNING) << "applyScaling Not implemented!"; } diff --git a/Source/Geometry/Particles/imstkRenderParticles.h b/Source/Geometry/Particles/imstkRenderParticles.h index 7199f0ff7b31d356f25ca7179d4986f542f0216c..45ec493781f699544f7c4c732327f0aa3ca1e697 100644 --- a/Source/Geometry/Particles/imstkRenderParticles.h +++ b/Source/Geometry/Particles/imstkRenderParticles.h @@ -21,15 +21,14 @@ #pragma once +#include "imstkGeometry.h" +#include "imstkMath.h" + #pragma warning( push ) #pragma warning( disable : 4201 ) -#include "glm/glm.hpp" +#include <glm/glm.hpp> #pragma warning( pop ) -#include "imstkGeometry.h" -#include "imstkMath.h" -//#include "imstkColor.h" - namespace imstk { /// diff --git a/Source/Geometry/Testing/imstkCubeTest.cpp b/Source/Geometry/Testing/imstkCubeTest.cpp index d317df1e162c2936b73a697c6f4800825427eff3..e1b384c1b67dafff2155376db690a5ef95c7f533 100644 --- a/Source/Geometry/Testing/imstkCubeTest.cpp +++ b/Source/Geometry/Testing/imstkCubeTest.cpp @@ -20,10 +20,9 @@ =========================================================================*/ #include "gtest/gtest.h" -#include "gmock/gmock.h" -#include "imstkMath.h" #include "imstkCube.h" + using namespace imstk; class imstkCubeTest : public ::testing::Test diff --git a/Source/Geometry/Testing/imstkGeometryTest.cpp b/Source/Geometry/Testing/imstkGeometryTest.cpp index 834996391ea245cf21b063d00f178ca4390350ba..db4679aacbde24f7ac0e0b6892b56e3dc79c9729 100644 --- a/Source/Geometry/Testing/imstkGeometryTest.cpp +++ b/Source/Geometry/Testing/imstkGeometryTest.cpp @@ -20,9 +20,7 @@ =========================================================================*/ #include "gtest/gtest.h" -#include "gmock/gmock.h" -#include "imstkMath.h" #include "imstkPlane.h" using namespace imstk; diff --git a/Source/Geometry/Testing/imstkPlaneTest.cpp b/Source/Geometry/Testing/imstkPlaneTest.cpp index 7d50d6a08e453defd0b1097e88570919103f79ac..579de4a2a641496671b715dc5a445961645e8630 100644 --- a/Source/Geometry/Testing/imstkPlaneTest.cpp +++ b/Source/Geometry/Testing/imstkPlaneTest.cpp @@ -20,10 +20,9 @@ =========================================================================*/ #include "gtest/gtest.h" -#include "gmock/gmock.h" -#include "imstkMath.h" #include "imstkPlane.h" + using namespace imstk; /// diff --git a/Source/Geometry/Testing/imstkSphereTest.cpp b/Source/Geometry/Testing/imstkSphereTest.cpp index 38fc48c358fba5aee70cff0bbd183cc2683d1791..48de88d1dec9241842a6b3a584ba1b038e96999a 100644 --- a/Source/Geometry/Testing/imstkSphereTest.cpp +++ b/Source/Geometry/Testing/imstkSphereTest.cpp @@ -20,10 +20,9 @@ =========================================================================*/ #include "gtest/gtest.h" -#include "gmock/gmock.h" -#include "imstkMath.h" #include "imstkSphere.h" + using namespace imstk; /// diff --git a/Source/Geometry/imstkGeometry.cpp b/Source/Geometry/imstkGeometry.cpp index 3d56ecfde0073d3ff0e6595053ef4994330ff866..ee75622b96510f6ee15d18747210519ba0fb6644 100644 --- a/Source/Geometry/imstkGeometry.cpp +++ b/Source/Geometry/imstkGeometry.cpp @@ -203,6 +203,12 @@ Geometry::setRotation(const Mat3d m) m_transformApplied = false; } +#include <glm/glm.hpp> +#include <glm/gtc/matrix_transform.hpp> +#define GLM_ENABLE_EXPERIMENTAL +#include <glm/gtx/matrix_decompose.hpp> +#include <glm/gtx/quaternion.hpp> + void Geometry::setRotation(const Quatd q) { @@ -243,6 +249,7 @@ Geometry::getType() const const std::string Geometry::getTypeName() const { + // /todo: create an actual object factory switch (m_type) { case Type::Plane: return "Plane"; @@ -259,6 +266,8 @@ Geometry::getTypeName() const case Type::DecalPool: return "DecalPool"; case Type::RenderParticles: return "RenderParticles"; case Type::ImageData: return "ImageData"; + case Type::SignedDistanceField: return "SignedDistanceField"; + case Type::CompositeImplicitGeometry: return "CompositeImplicitGeometry"; default: LOG(FATAL) << "Mesh type to string has not been completely implemented"; return ""; diff --git a/Source/Geometry/imstkGeometry.h b/Source/Geometry/imstkGeometry.h index 038dc8bffa68e05b9b26b1272379b0a803153bb7..af11def3f15739c555a161fd37e40c2c54ff56b9 100644 --- a/Source/Geometry/imstkGeometry.h +++ b/Source/Geometry/imstkGeometry.h @@ -21,7 +21,9 @@ #pragma once +#include "imstkEventObject.h" #include "imstkMath.h" +#include "imstkTypes.h" #include <tbb/concurrent_unordered_set.h> @@ -36,7 +38,7 @@ class SpinLock; /// \class Geometry /// \brief Base class for any geometrical representation /// -class Geometry +class Geometry : public EventObject { public: /// @@ -57,7 +59,9 @@ public: Decal, DecalPool, RenderParticles, - ImageData + ImageData, + SignedDistanceField, + CompositeImplicitGeometry }; /// @@ -90,7 +94,7 @@ public: /// /// \brief Destructor /// - virtual ~Geometry(); + virtual ~Geometry() override; /// /// \brief Print @@ -100,10 +104,11 @@ public: /// /// \brief Returns the volume of the geometry (if valid) /// - virtual double getVolume() const = 0; + virtual double getVolume() const { return 0.0; }; /// /// \brief Compute the bounding box for the geometry + /// \todo Padding should not be here /// virtual void computeBoundingBox(Vec3d& lowerCorner, Vec3d& upperCorner, const double paddingPercent = 0.0) const; @@ -181,6 +186,13 @@ public: /// static uint32_t getTotalNumberGeometries() { return s_NumGeneratedGegometries; } + /// + /// \brief Post modified event + /// + void modified() { this->postEvent(Event(EventType::Modified)); } + + virtual void updatePostTransformData() const { } + protected: /// /// \brief Get a unique ID for the new generated geometry object @@ -204,20 +216,20 @@ protected: friend class VulkanRenderDelegate; friend class VulkanRenderer; - virtual void applyTranslation(const Vec3d t) = 0; - virtual void applyRotation(const Mat3d r) = 0; - virtual void applyScaling(const double s) = 0; - virtual void updatePostTransformData() const = 0; + virtual void applyTranslation(const Vec3d imstkNotUsed(t)) { } + virtual void applyRotation(const Mat3d imstkNotUsed(r)) { } + virtual void applyScaling(const double imstkNotUsed(s)) { } Type m_type; ///> Type of geometry std::string m_name; ///> Unique name for each geometry uint32_t m_geometryIndex; ///> Unique ID assigned to each geometry upon construction - bool m_dataModified = false; bool m_transformModified = false; mutable bool m_transformApplied = true; RigidTransform3d m_transform; ///> Transformation matrix double m_scaling = 1.0; + + bool m_dataModified = true; }; } //imstk diff --git a/Source/Geometry/imstkGeometryUtilities.cpp b/Source/Geometry/imstkGeometryUtilities.cpp index 7ee553d0f0da636cea10168ab2c19244020fd950..6a7508325e324abdd755527645776a55ae4f4458 100644 --- a/Source/Geometry/imstkGeometryUtilities.cpp +++ b/Source/Geometry/imstkGeometryUtilities.cpp @@ -20,33 +20,197 @@ =========================================================================*/ #include "imstkGeometryUtilities.h" +#include "imstkDataArray.h" #include "imstkHexahedralMesh.h" +#include "imstkImageData.h" #include "imstkLineMesh.h" -#include "imstkPointSet.h" +#include "imstkLogger.h" +#include "imstkParallelUtils.h" #include "imstkSurfaceMesh.h" #include "imstkTetrahedralMesh.h" +#include "imstkCube.h" +#include "imstkSphere.h" #include <vtkAppendPolyData.h> -#include <vtkCleanPolyData.h> -#include <vtkDataSet.h> -#include <vtkPolyData.h> -#include <vtkPointSet.h> -#include <vtkExtractEdges.h> -#include <vtkLinearSubdivisionFilter.h> -#include <vtkLoopSubdivisionFilter.h> +#include <vtkCharArray.h> +#include <vtkCubeSource.h> +#include <vtkDoubleArray.h> +#include <vtkFeatureEdges.h> +#include <vtkFloatArray.h> +#include <vtkImageData.h> +#include <vtkMassProperties.h> #include <vtkPointData.h> -#include <vtkSelectEnclosedPoints.h> -#include <vtkSmoothPolyDataFilter.h> +#include <vtkShortArray.h> +#include <vtkSphereSource.h> +#include <vtkTransform.h> +#include <vtkTransformFilter.h> #include <vtkTriangleFilter.h> -#include <vtkUnstructuredGrid.h> #include <vtkUnsignedCharArray.h> +#include <vtkUnsignedIntArray.h> +#include <vtkUnsignedLongArray.h> +#include <vtkUnsignedShortArray.h> +#include <vtkUnstructuredGrid.h> + +static vtkSmartPointer<vtkDataArray> +makeVtkDataArray(unsigned char type) +{ + vtkSmartPointer<vtkDataArray> arr = nullptr; + switch (type) + { + case VTK_CHAR: + arr = vtkSmartPointer<vtkCharArray>::New(); + break; + case VTK_UNSIGNED_CHAR: + arr = vtkSmartPointer<vtkUnsignedCharArray>::New(); + break; + case VTK_SHORT: + arr = vtkSmartPointer<vtkShortArray>::New(); + break; + case VTK_UNSIGNED_SHORT: + arr = vtkSmartPointer<vtkUnsignedShortArray>::New(); + break; + case VTK_INT: + arr = vtkSmartPointer<vtkIntArray>::New(); + break; + case VTK_UNSIGNED_INT: + arr = vtkSmartPointer<vtkUnsignedIntArray>::New(); + break; + case VTK_FLOAT: + arr = vtkSmartPointer<vtkFloatArray>::New(); + break; + case VTK_DOUBLE: + arr = vtkSmartPointer<vtkDoubleArray>::New(); + break; + case VTK_LONG_LONG: + arr = vtkSmartPointer<vtkLongLongArray>::New(); + break; + case VTK_UNSIGNED_LONG_LONG: + arr = vtkSmartPointer<vtkUnsignedLongArray>::New(); + break; + default: + LOG(WARNING) << "Unknown scalar type"; + break; + } + ; + return arr; +} #include <vtkFloatArray.h> namespace imstk { +vtkSmartPointer<vtkDataArray> +GeometryUtils::coupleVtkDataArray(std::shared_ptr<AbstractDataArray> imstkArray) +{ + CHECK(imstkArray != nullptr) << "AbstractDataArray provided is not valid!"; + CHECK(imstkArray->getVoidPointer() != nullptr) << "AbstractDataArray data provided is not valid!"; + + // Create corresponding data array + vtkSmartPointer<vtkDataArray> arr = makeVtkDataArray(imstkToVtkScalarType[imstkArray->getScalarType()]); + arr->SetVoidArray(imstkArray->getVoidPointer(), imstkArray->size(), 1); + + return arr; +} + +vtkSmartPointer<vtkImageData> +GeometryUtils::coupleVtkImageData(std::shared_ptr<ImageData> imageData) +{ + CHECK(imageData != nullptr) << "ImageData provided is not valid!"; + + // VTK puts center of min voxel at origin of world space, we put min of bot voxel at origin + std::shared_ptr<AbstractDataArray> arr = imageData->getScalars(); + vtkSmartPointer<vtkDataArray> vtkArr = coupleVtkDataArray(arr); + + vtkSmartPointer<vtkImageData> imageDataVtk = vtkSmartPointer<vtkImageData>::New(); + imageDataVtk->SetDimensions(imageData->getDimensions().data()); + imageDataVtk->SetSpacing(imageData->getSpacing().data()); + const Vec3d vtkOrigin = imageData->getOrigin() + imageData->getSpacing() * 0.5; + imageDataVtk->SetOrigin(vtkOrigin.data()); + imageDataVtk->SetNumberOfScalarComponents(imageData->getNumComponents(), imageDataVtk->GetInformation()); + imageDataVtk->SetScalarType(imstkToVtkScalarType[arr->getScalarType()], imageDataVtk->GetInformation()); + imageDataVtk->GetPointData()->SetScalars(vtkArr); + return imageDataVtk; +} + +vtkSmartPointer<vtkDataArray> +GeometryUtils::copyToVtkDataArray(std::shared_ptr<AbstractDataArray> imstkArray, int numComps) +{ + CHECK(imstkArray != nullptr) << "AbstractDataArray provided is not valid!"; + + // Create resulting data array + vtkSmartPointer<vtkDataArray> arr = makeVtkDataArray(imstkToVtkScalarType[imstkArray->getScalarType()]); + arr->SetNumberOfComponents(numComps); + arr->SetNumberOfValues(imstkArray->size()); + switch (imstkArray->getScalarType()) + { + TemplateMacro(std::copy_n(static_cast<IMSTK_TT*>(imstkArray->getVoidPointer()), imstkArray->size(), static_cast<IMSTK_TT*>(arr->GetVoidPointer(0))); ); + default: + LOG(WARNING) << "Unknown scalar type"; + break; + } + + return arr; +} + +std::shared_ptr<AbstractDataArray> +GeometryUtils::copyToDataArray(vtkSmartPointer<vtkDataArray> vtkArray) +{ + CHECK(vtkArray != nullptr) << "vtkDataArray provided is not valid!"; + + std::shared_ptr<AbstractDataArray> arr = nullptr; + + // Create and copy the array + switch (vtkToImstkScalarType[vtkArray->GetDataType()]) + { + TemplateMacro(arr = std::make_shared<DataArray<IMSTK_TT>>(vtkArray->GetNumberOfValues()); + std::copy_n(static_cast<IMSTK_TT*>(vtkArray->GetVoidPointer(0)), vtkArray->GetNumberOfValues(), static_cast<IMSTK_TT*>(arr->getVoidPointer())); ); + default: + LOG(WARNING) << "Unknown scalar type"; + break; + } + return arr; +} + +std::unique_ptr<ImageData> +GeometryUtils::copyToImageData(vtkSmartPointer<vtkImageData> vtkImage) +{ + CHECK(vtkImage != nullptr) << "vtkImageData provided is not valid!"; + + double* spacingPtr = vtkImage->GetSpacing(); + const Vec3d spacing = Vec3d(spacingPtr[0], spacingPtr[1], spacingPtr[2]); + // vtk origin is not bounds and vtk origin is not actual origin + double* bounds = vtkImage->GetBounds(); + // image data origin starts at center of first voxel + const Vec3d origin = Vec3d(bounds[0], bounds[2], bounds[4]) - spacing * 0.5; + + std::unique_ptr<ImageData> imageData = std::make_unique<ImageData>(); + imageData->setScalars(copyToDataArray(vtkImage->GetPointData()->GetScalars()), + vtkImage->GetNumberOfScalarComponents(), vtkImage->GetDimensions()); + imageData->setSpacing(spacing); + imageData->setOrigin(origin); + return imageData; +} + +vtkSmartPointer<vtkImageData> +GeometryUtils::copyToVtkImageData(std::shared_ptr<ImageData> imageData) +{ + CHECK(imageData != nullptr) << "ImageData provided is not valid!"; + + // Our image data does not use vtk extents + const Vec3i& dim = imageData->getDimensions(); + + vtkSmartPointer<vtkImageData> imageDataVtk = vtkSmartPointer<vtkImageData>::New(); + imageDataVtk->SetSpacing(imageData->getSpacing().data()); + const Vec3d vtkOrigin = imageData->getOrigin() + imageData->getSpacing() * 0.5; + imageDataVtk->SetOrigin(vtkOrigin.data()); + imageDataVtk->SetExtent(0, dim[0] - 1, 0, dim[1] - 1, 0, dim[2] - 1); + imageDataVtk->AllocateScalars(imstkToVtkScalarType[imageData->getScalarType()], imageData->getNumComponents()); + imageDataVtk->GetPointData()->SetScalars(copyToVtkDataArray(imageData->getScalars(), imageData->getNumComponents())); + return imageDataVtk; +} + std::unique_ptr<PointSet> -GeometryUtils::convertVtkPointSetToPointSet(const vtkSmartPointer<vtkPointSet> vtkMesh) +GeometryUtils::copyToPointSet(vtkSmartPointer<vtkPointSet> vtkMesh) { CHECK(vtkMesh != nullptr) << "vtkPolyData provided is not valid!"; @@ -68,7 +232,7 @@ GeometryUtils::convertVtkPointSetToPointSet(const vtkSmartPointer<vtkPointSet> v } std::unique_ptr<SurfaceMesh> -GeometryUtils::convertVtkPolyDataToSurfaceMesh(const vtkSmartPointer<vtkPolyData> vtkMesh) +GeometryUtils::copyToSurfaceMesh(vtkSmartPointer<vtkPolyData> vtkMesh) { CHECK(vtkMesh != nullptr) << "vtkPolyData provided is not valid!"; @@ -102,7 +266,7 @@ GeometryUtils::convertVtkPolyDataToSurfaceMesh(const vtkSmartPointer<vtkPolyData } std::unique_ptr<LineMesh> -GeometryUtils::convertVtkPolyDataToLineMesh(const vtkSmartPointer<vtkPolyData> vtkMesh) +GeometryUtils::copyToLineMesh(vtkSmartPointer<vtkPolyData> vtkMesh) { CHECK(vtkMesh != nullptr) << "vtkPolyData provided is not valid!"; @@ -127,7 +291,7 @@ GeometryUtils::convertVtkPolyDataToLineMesh(const vtkSmartPointer<vtkPolyData> v } vtkSmartPointer<vtkPointSet> -GeometryUtils::convertPointSetToVtkPointSet(const std::shared_ptr<PointSet> imstkMesh) +GeometryUtils::copyToVtkPointSet(std::shared_ptr<PointSet> imstkMesh) { vtkNew<vtkPoints> points; copyVerticesToVtk(imstkMesh->getVertexPositions(), points.Get()); @@ -138,7 +302,7 @@ GeometryUtils::convertPointSetToVtkPointSet(const std::shared_ptr<PointSet> imst } vtkSmartPointer<vtkPolyData> -GeometryUtils::convertLineMeshToVtkPolyData(const std::shared_ptr<LineMesh> imstkMesh) +GeometryUtils::copyToVtkPolyData(std::shared_ptr<LineMesh> imstkMesh) { vtkNew<vtkPoints> points; copyVerticesToVtk(imstkMesh->getVertexPositions(), points.Get()); @@ -153,7 +317,7 @@ GeometryUtils::convertLineMeshToVtkPolyData(const std::shared_ptr<LineMesh> imst } vtkSmartPointer<vtkPolyData> -GeometryUtils::convertSurfaceMeshToVtkPolyData(const std::shared_ptr<SurfaceMesh> imstkMesh) +GeometryUtils::copyToVtkPolyData(std::shared_ptr<SurfaceMesh> imstkMesh) { vtkNew<vtkPoints> points; copyVerticesToVtk(imstkMesh->getVertexPositions(), points.Get()); @@ -169,7 +333,7 @@ GeometryUtils::convertSurfaceMeshToVtkPolyData(const std::shared_ptr<SurfaceMesh } vtkSmartPointer<vtkUnstructuredGrid> -GeometryUtils::convertTetrahedralMeshToVtkUnstructuredGrid(const std::shared_ptr<TetrahedralMesh> imstkMesh) +GeometryUtils::copyToVtkUnstructuredGrid(std::shared_ptr<TetrahedralMesh> imstkMesh) { vtkNew<vtkPoints> points; copyVerticesToVtk(imstkMesh->getVertexPositions(), points.Get()); @@ -205,7 +369,7 @@ GeometryUtils::convertTetrahedralMeshToVtkUnstructuredGrid(const std::shared_ptr } vtkSmartPointer<vtkUnstructuredGrid> -GeometryUtils::convertHexahedralMeshToVtkUnstructuredGrid(const std::shared_ptr<HexahedralMesh> imstkMesh) +GeometryUtils::copyToVtkUnstructuredGrid(std::shared_ptr<HexahedralMesh> imstkMesh) { vtkNew<vtkPoints> points; copyVerticesToVtk(imstkMesh->getVertexPositions(), points.Get()); @@ -220,7 +384,7 @@ GeometryUtils::convertHexahedralMeshToVtkUnstructuredGrid(const std::shared_ptr< } std::unique_ptr<VolumetricMesh> -GeometryUtils::convertVtkUnstructuredGridToVolumetricMesh(vtkSmartPointer<vtkUnstructuredGrid> vtkMesh) +GeometryUtils::copyToVolumetricMesh(vtkSmartPointer<vtkUnstructuredGrid> vtkMesh) { CHECK(vtkMesh != nullptr) << "vtkUnstructuredGrid provided is not valid!"; @@ -327,8 +491,12 @@ GeometryUtils::copyPointDataFromVtk(vtkPointData* const pointData, std::map<std: for (int i = 0; i < pointData->GetNumberOfArrays(); ++i) { - vtkDataArray* array = pointData->GetArray(i); - std::string name = array->GetName(); + vtkDataArray* array = pointData->GetArray(i); + std::string name = ""; + if (array->GetName() != NULL) + { + name = array->GetName(); + } int nbrOfComp = array->GetNumberOfComponents(); vtkIdType nbrOfTuples = array->GetNumberOfTuples(); StdVectorOfVectorf data; @@ -347,126 +515,66 @@ GeometryUtils::copyPointDataFromVtk(vtkPointData* const pointData, std::map<std: } } -std::unique_ptr<SurfaceMesh> -GeometryUtils::combineSurfaceMesh(std::shared_ptr<SurfaceMesh> surfaceMesh1, std::shared_ptr<SurfaceMesh> surfaceMesh2) +std::shared_ptr<SurfaceMesh> +GeometryUtils::toCubeSurfaceMesh(std::shared_ptr<Cube> cube) { - vtkNew<vtkAppendPolyData> filter; - filter->AddInputData(convertSurfaceMeshToVtkPolyData(surfaceMesh1)); - filter->AddInputData(convertSurfaceMeshToVtkPolyData(surfaceMesh2)); - filter->Update(); - - return convertVtkPolyDataToSurfaceMesh(filter->GetOutput()); + vtkNew<vtkCubeSource> cubeSource; + cubeSource->SetCenter(cube->getPosition(Geometry::DataType::PreTransform).data()); + cubeSource->SetXLength(cube->getWidth()); + cubeSource->SetYLength(cube->getWidth()); + cubeSource->SetZLength(cube->getWidth()); + cubeSource->Update(); + + Mat4d mat; + mat.setIdentity(); + mat.block<3, 3>(0, 0) = cube->getRotation(); + + vtkNew<vtkTransform> transform; + transform->SetMatrix(mat.data()); + + vtkNew<vtkTransformFilter> transformCube; + transformCube->SetInputData(cubeSource->GetOutput()); + transformCube->SetTransform(transform); + transformCube->Update(); + vtkNew<vtkTriangleFilter> triangulate; + triangulate->SetInputData(transformCube->GetOutput()); + triangulate->Update(); + return copyToSurfaceMesh(triangulate->GetOutput()); } -std::unique_ptr<LineMesh> -GeometryUtils::surfaceMeshToLineMesh(std::shared_ptr<SurfaceMesh> surfaceMesh) +std::shared_ptr<SurfaceMesh> +GeometryUtils::toUVSphereSurfaceMesh(std::shared_ptr<Sphere> sphere, + const unsigned int phiDivisions, const unsigned int thetaDivisions) { - vtkNew<vtkExtractEdges> filter; - filter->SetInputData(convertSurfaceMeshToVtkPolyData(surfaceMesh)); - filter->Update(); - - vtkNew<vtkTriangleFilter> triangleFilter; - triangleFilter->SetInputData(filter->GetOutput()); - triangleFilter->Update(); - - return convertVtkPolyDataToLineMesh(triangleFilter->GetOutput()); + vtkNew<vtkSphereSource> sphereSource; + sphereSource->SetCenter(sphere->getPosition(Geometry::DataType::PreTransform).data()); + sphereSource->SetRadius(sphere->getRadius()); + sphereSource->SetPhiResolution(phiDivisions); + sphereSource->SetThetaResolution(thetaDivisions); + sphereSource->Update(); + + return copyToSurfaceMesh(sphereSource->GetOutput()); } -std::unique_ptr<SurfaceMesh> -GeometryUtils::cleanSurfaceMesh(std::shared_ptr<SurfaceMesh> surfaceMesh) +int +GeometryUtils::getOpenEdgeCount(std::shared_ptr<SurfaceMesh> surfMesh) { - vtkNew<vtkCleanPolyData> filter; - filter->SetInputData(convertSurfaceMeshToVtkPolyData(surfaceMesh)); - filter->Update(); - return convertVtkPolyDataToSurfaceMesh(filter->GetOutput()); + vtkNew<vtkFeatureEdges> checkClosed; + checkClosed->SetInputData(GeometryUtils::copyToVtkPolyData(surfMesh)); + checkClosed->FeatureEdgesOff(); + checkClosed->BoundaryEdgesOn(); + checkClosed->NonManifoldEdgesOn(); + checkClosed->Update(); + return checkClosed->GetOutput()->GetNumberOfCells(); } -std::unique_ptr<PointSet> -GeometryUtils::getEnclosedPoints(std::shared_ptr<SurfaceMesh> surfaceMesh, std::shared_ptr<PointSet> pointSet, bool insideOut) +double +GeometryUtils::getVolume(std::shared_ptr<SurfaceMesh> surfMesh) { - vtkNew<vtkSelectEnclosedPoints> filter; - filter->SetInputData(convertPointSetToVtkPointSet(pointSet)); - filter->SetSurfaceData(convertSurfaceMeshToVtkPolyData(surfaceMesh)); - filter->SetTolerance(0.0); - filter->SetInsideOut(insideOut); - filter->Update(); - vtkSmartPointer<vtkPointSet> vtkResults = vtkPointSet::SafeDownCast(filter->GetOutput()); - - StdVectorOfVec3d points; - points.reserve(vtkResults->GetNumberOfPoints()); - for (vtkIdType i = 0; i < vtkResults->GetNumberOfPoints(); i++) - { - if (filter->IsInside(i)) - { - double pt[3]; - vtkResults->GetPoint(i, pt); - points.push_back(Vec3d(pt[0], pt[1], pt[2])); - } - } - points.shrink_to_fit(); - - std::unique_ptr<PointSet> results = std::make_unique<PointSet>(); - results->setInitialVertexPositions(points); - results->setVertexPositions(points); - return results; -} - -void -GeometryUtils::testEnclosedPoints(std::vector<bool>& results, std::shared_ptr<SurfaceMesh> surfaceMesh, std::shared_ptr<PointSet> pointSet, const bool insideOut) -{ - vtkNew<vtkSelectEnclosedPoints> filter; - filter->SetInputData(convertPointSetToVtkPointSet(pointSet)); - filter->SetSurfaceData(convertSurfaceMeshToVtkPolyData(surfaceMesh)); - filter->SetTolerance(0.0); - filter->SetInsideOut(insideOut); - filter->Update(); - vtkUnsignedCharArray* arr = vtkUnsignedCharArray::SafeDownCast(filter->GetOutput()->GetPointData()->GetArray("SelectedPoints")); - - results.resize(arr->GetNumberOfValues()); - for (vtkIdType i = 0; i < arr->GetNumberOfValues(); i++) - { - results[i] = (arr->GetValue(i) ? true : false); - } -} - -std::unique_ptr<SurfaceMesh> -GeometryUtils::smoothSurfaceMesh(std::shared_ptr<SurfaceMesh> surfaceMesh, - const smoothPolydataConfig& c) -{ - vtkNew<vtkSmoothPolyDataFilter> filter; - filter->SetInputData(convertSurfaceMeshToVtkPolyData(surfaceMesh)); - filter->SetNumberOfIterations(c.numberOfIterations); - filter->SetRelaxationFactor(c.relaxationFactor); - filter->SetConvergence(c.convergence); - filter->SetFeatureAngle(c.featureAngle); - filter->SetEdgeAngle(c.edgeAngle); - filter->SetFeatureEdgeSmoothing(c.featureEdgeSmoothing); - filter->SetBoundarySmoothing(c.boundarySmoothing); - filter->Update(); - - return convertVtkPolyDataToSurfaceMesh(filter->GetOutput()); -} - -std::unique_ptr<SurfaceMesh> -GeometryUtils::linearSubdivideSurfaceMesh(std::shared_ptr<SurfaceMesh> surfaceMesh, const int numSubdivisions) -{ - vtkNew<vtkLinearSubdivisionFilter> filter; - filter->SetInputData(convertSurfaceMeshToVtkPolyData(surfaceMesh)); - filter->SetNumberOfSubdivisions(numSubdivisions); - filter->Update(); - - return convertVtkPolyDataToSurfaceMesh(filter->GetOutput()); -} - -std::unique_ptr<SurfaceMesh> -GeometryUtils::loopSubdivideSurfaceMesh(std::shared_ptr<SurfaceMesh> surfaceMesh, const int numSubdivisions) -{ - vtkNew<vtkLoopSubdivisionFilter> filter; - filter->SetInputData(convertSurfaceMeshToVtkPolyData(surfaceMesh)); - filter->SetNumberOfSubdivisions(numSubdivisions); - filter->Update(); - - return convertVtkPolyDataToSurfaceMesh(filter->GetOutput()); + vtkNew<vtkMassProperties> massProps; + massProps->SetInputData(copyToVtkPolyData(surfMesh)); + massProps->Update(); + return massProps->GetVolume(); } namespace // anonymous namespace @@ -864,7 +972,7 @@ markPointsInsideAndOut(std::vector<bool>& isInside, /// /// \brief Given a set of uniformly spaced points, mark them as inside (true) and outside. -/// It makes uses of ray-tracing but skips points based on the nearest distance between current point and the surface. +/// It makes uses of ray-casting but skips points based on the nearest distance between current point and the surface. /// /// \param surfaceMesh a \ref SurfaceMesh /// \param coords a set of points to be tested @@ -872,8 +980,6 @@ markPointsInsideAndOut(std::vector<bool>& isInside, /// \param ny number of points in y-direction /// \param nz number of points in z-direction /// -/// \note this function cannot be const because PointSet::computeBoundingBox, called inside, is not. -/// void markPointsInsideAndOut(std::vector<bool>& isInside, const SurfaceMesh& surfaceMesh, diff --git a/Source/Geometry/imstkGeometryUtilities.h b/Source/Geometry/imstkGeometryUtilities.h index bfccaac1e99d30411354d339cc664e2db40ade31..9679eecd85098b3e572b72705729c34322b616b5 100644 --- a/Source/Geometry/imstkGeometryUtilities.h +++ b/Source/Geometry/imstkGeometryUtilities.h @@ -21,20 +21,21 @@ #pragma once -#include "imstkLogger.h" #include "imstkMath.h" -#include "imstkParallelUtils.h" - -#include "vtkSmartPointer.h" - +#include "imstkTypes.h" #include <memory> #include <numeric> #include <queue> -#include <unordered_set> #include <set> +#include <unordered_map> +#include <unordered_set> +#include <vtkSmartPointer.h> +#include <vtkType.h> +class vtkDataArray; class vtkCellArray; class vtkPolyData; +class vtkImageData; class vtkPointData; class vtkPoints; class vtkPointSet; @@ -42,6 +43,8 @@ class vtkUnstructuredGrid; namespace imstk { +class AbstractDataArray; +class ImageData; class HexahedralMesh; class LineMesh; class PointSet; @@ -49,52 +52,113 @@ class SurfaceMesh; class TetrahedralMesh; class VolumetricMesh; +class Cube; +class Sphere; + +/// +/// \brief Contains a set of free functions for processing geometry +/// also contains a set of conversion and coupling functions for VTK +/// namespace GeometryUtils { +static std::unordered_map<int, ScalarType> vtkToImstkScalarType = +{ + { VTK_VOID, IMSTK_VOID }, + { VTK_CHAR, IMSTK_CHAR }, + { VTK_UNSIGNED_CHAR, IMSTK_UNSIGNED_CHAR }, + { VTK_SHORT, IMSTK_SHORT }, + { VTK_UNSIGNED_SHORT, IMSTK_UNSIGNED_SHORT }, + { VTK_INT, IMSTK_INT }, + { VTK_UNSIGNED_INT, IMSTK_UNSIGNED_INT }, + { VTK_LONG, IMSTK_LONG }, + { VTK_UNSIGNED_LONG, IMSTK_UNSIGNED_LONG }, + { VTK_FLOAT, IMSTK_FLOAT }, + { VTK_DOUBLE, IMSTK_DOUBLE }, + { VTK_LONG_LONG, IMSTK_LONG_LONG }, + { VTK_UNSIGNED_LONG_LONG, IMSTK_UNSIGNED_LONG_LONG } +}; +static std::unordered_map<ScalarType, int> imstkToVtkScalarType = +{ + { IMSTK_VOID, VTK_VOID }, + { IMSTK_CHAR, VTK_CHAR }, + { IMSTK_UNSIGNED_CHAR, VTK_UNSIGNED_CHAR }, + { IMSTK_SHORT, VTK_SHORT }, + { IMSTK_UNSIGNED_SHORT, VTK_UNSIGNED_SHORT }, + { IMSTK_INT, VTK_INT }, + { IMSTK_UNSIGNED_INT, VTK_UNSIGNED_INT }, + { IMSTK_LONG, VTK_LONG }, + { IMSTK_UNSIGNED_LONG, VTK_UNSIGNED_LONG }, + { IMSTK_FLOAT, VTK_FLOAT }, + { IMSTK_DOUBLE, VTK_DOUBLE }, + { IMSTK_LONG_LONG, VTK_LONG_LONG }, + { IMSTK_UNSIGNED_LONG_LONG, VTK_UNSIGNED_LONG_LONG } +}; + +/// +/// \brief Coupling functions, these create vtk data objects that point to our data objects +/// thus no copying is done here. +/// +vtkSmartPointer<vtkDataArray> coupleVtkDataArray(std::shared_ptr<AbstractDataArray> imstkArray); +vtkSmartPointer<vtkImageData> coupleVtkImageData(std::shared_ptr<ImageData> imstkImageData); + +/// +/// \brief Copy functions, these copy to/from vtk data objects +/// +vtkSmartPointer<vtkDataArray> copyToVtkDataArray(std::shared_ptr<AbstractDataArray> imstkArray, int numComps = 1); +std::shared_ptr<AbstractDataArray> copyToDataArray(vtkSmartPointer<vtkDataArray> vtkArray); + +std::unique_ptr<ImageData> copyToImageData(vtkSmartPointer<vtkImageData> imageDataVtk); +vtkSmartPointer<vtkImageData> copyToVtkImageData(std::shared_ptr<ImageData> imageData); + /// /// \brief Converts vtk polydata into a imstk point set /// -std::unique_ptr<PointSet> convertVtkPointSetToPointSet(const vtkSmartPointer<vtkPointSet> vtkMesh); +std::unique_ptr<PointSet> copyToPointSet(vtkSmartPointer<vtkPointSet> vtkMesh); /// /// \brief Converts vtk polydata into a imstk surface mesh /// -std::unique_ptr<SurfaceMesh> convertVtkPolyDataToSurfaceMesh(const vtkSmartPointer<vtkPolyData> vtkMesh); +std::unique_ptr<SurfaceMesh> copyToSurfaceMesh(vtkSmartPointer<vtkPolyData> vtkMesh); /// /// \brief Converts vtk polydata into a imstk surface mesh /// -std::unique_ptr<LineMesh> convertVtkPolyDataToLineMesh(const vtkSmartPointer<vtkPolyData> vtkMesh); +std::unique_ptr<LineMesh> copyToLineMesh(vtkSmartPointer<vtkPolyData> vtkMesh); /// /// \brief Get imstk volumetric mesh given vtkUnstructuredGrid as input /// -std::unique_ptr<VolumetricMesh> convertVtkUnstructuredGridToVolumetricMesh(const vtkSmartPointer<vtkUnstructuredGrid> vtkMesh); +std::unique_ptr<VolumetricMesh> copyToVolumetricMesh(vtkSmartPointer<vtkUnstructuredGrid> vtkMesh); + +/// +/// \brief Smart copy will try to tell the type of the input mesh to convert to imstk +/// +//std::shared_ptr<PointSet> smartCopyToVtkPolyData(vtkSmartPointer<vtkPointSet> vtkMesh); /// /// \brief Converts imstk point set into a vtk polydata /// -vtkSmartPointer<vtkPointSet> convertPointSetToVtkPointSet(const std::shared_ptr<PointSet> imstkMesh); +vtkSmartPointer<vtkPointSet> copyToVtkPointSet(std::shared_ptr<PointSet> imstkMesh); /// /// \brief Converts imstk line mesh into a vtk polydata /// -vtkSmartPointer<vtkPolyData> convertLineMeshToVtkPolyData(const std::shared_ptr<LineMesh> imstkMesh); +vtkSmartPointer<vtkPolyData> copyToVtkPolyData(std::shared_ptr<LineMesh> imstkMesh); /// /// \brief Converts imstk surface mesh into a vtk polydata /// -vtkSmartPointer<vtkPolyData> convertSurfaceMeshToVtkPolyData(const std::shared_ptr<SurfaceMesh> imstkMesh); +vtkSmartPointer<vtkPolyData> copyToVtkPolyData(std::shared_ptr<SurfaceMesh> imstkMesh); /// /// \brief Converts imstk tetrahedral mesh into a vtk unstructured grid /// -vtkSmartPointer<vtkUnstructuredGrid> convertTetrahedralMeshToVtkUnstructuredGrid(const std::shared_ptr<TetrahedralMesh> imstkMesh); +vtkSmartPointer<vtkUnstructuredGrid> copyToVtkUnstructuredGrid(std::shared_ptr<TetrahedralMesh> imstkMesh); /// /// \brief Converts imstk hexahedral mesh into a vtk unstructured grid /// -vtkSmartPointer<vtkUnstructuredGrid> convertHexahedralMeshToVtkUnstructuredGrid(const std::shared_ptr<HexahedralMesh> imstkMesh); +vtkSmartPointer<vtkUnstructuredGrid> copyToVtkUnstructuredGrid(std::shared_ptr<HexahedralMesh> imstkMesh); /// /// \brief Copy from vtk points to a imstk vertices array (StdVectorOfVec3d) @@ -124,79 +188,34 @@ void copyCellsFromVtk(vtkCellArray* vtkCells, std::vector<std::array<size_t, dim void copyPointDataFromVtk(vtkPointData* const pointData, std::map<std::string, StdVectorOfVectorf>& dataMap); /// -/// \brief Combines two input surface meshes -/// Refer <a href="https://vtk.org/doc/nightly/html/classvtkAppendPolyData.html#details">vtkAppendPolyData</a> class -/// for more details -/// -/// -std::unique_ptr<SurfaceMesh> combineSurfaceMesh(std::shared_ptr<SurfaceMesh> surfaceMesh1, std::shared_ptr<SurfaceMesh> surfaceMesh2); - -/// -/// \brief Converts an imstk SurfaceMesh to a LineMesh, removing duplicate edges. Cell indices not preserved +/// \brief Produces SurfaceMesh cube from imstkCube /// -std::unique_ptr<LineMesh> surfaceMeshToLineMesh(std::shared_ptr<SurfaceMesh> surfaceMesh); +std::shared_ptr<SurfaceMesh> toCubeSurfaceMesh(std::shared_ptr<Cube> cube); /// -/// \brief Removes duplicate edges & points in poly data -/// Refer <a href="https://vtk.org/doc/nightly/html/classvtkCleanPolyData.html#details">vtkCleanPolyData</a> class -/// for more details +/// \brief UV sphere from imstkSphere /// -std::unique_ptr<SurfaceMesh> cleanSurfaceMesh(std::shared_ptr<SurfaceMesh> surfaceMesh); +std::shared_ptr<SurfaceMesh> toUVSphereSurfaceMesh(std::shared_ptr<Sphere> sphere, + const unsigned int phiDivisions, const unsigned int thetaDivisions); /// -/// \brief Returns points in pointSet within the provided surfaceMesh -/// Refer <a href="https://vtk.org/doc/nightly/html/classvtkSelectEnclosedPoints.html#details">vtkSelectEnclosedPoints</a> class -/// for more details +/// \brief Returns the number of open edges, use to tell if manifold (==0) /// -std::unique_ptr<PointSet> getEnclosedPoints(std::shared_ptr<SurfaceMesh> surfaceMesh, std::shared_ptr<PointSet> pointSet, const bool insideOut = false); +int getOpenEdgeCount(std::shared_ptr<SurfaceMesh> surfMesh); /// -/// \brief Returns array indicating if point is enclosed or not -/// Refer <a href="https://vtk.org/doc/nightly/html/classvtkSelectEnclosedPoints.html#details">vtkSelectEnclosedPoints</a> class -/// for more details -/// -void testEnclosedPoints(std::vector<bool>& results, std::shared_ptr<SurfaceMesh> surfaceMesh, std::shared_ptr<PointSet> pointSet, const bool insideOut = false); - +/// \brief Returns if the surface is closed or not /// -/// \brief Reverse the winding of a SurfaceMesh -/// Refer <a href="https://vtk.org/doc/nightly/html/classvtkSelectEnclosedPoints.html#details">vtkSelectEnclosedPoints</a> class -/// - -/// -/// \brief Config for smooth polydata filter -/// -struct smoothPolydataConfig +inline bool +isClosed(std::shared_ptr<SurfaceMesh> surfMesh) { - int numberOfIterations = 20; - double relaxationFactor = 0.01; - double convergence = 0.0; - double featureAngle = 45.0; - double edgeAngle = 15.0; - bool featureEdgeSmoothing = false; - bool boundarySmoothing = true; -}; - -/// -/// \brief Smooths a SurfaceMesh using laplacian smoothening -/// Refer <a href="https://vtk.org/doc/nightly/html/classvtkSmoothPolyDataFilter.html#details">vtkSmoothPolyDataFilter</a> -/// for more details -/// -std::unique_ptr<SurfaceMesh> smoothSurfaceMesh(std::shared_ptr<SurfaceMesh> surfaceMesh, - const smoothPolydataConfig& c); - -/// -/// \brief Sub-divdes a SurfaceMesh using linear subdivision -/// Refer <a href="https://vtk.org/doc/nightly/html/classvtkLinearSubdivisionFilter.html#details">vtk linear subdivision</a> -/// for more details -/// -std::unique_ptr<SurfaceMesh> linearSubdivideSurfaceMesh(std::shared_ptr<SurfaceMesh> surfaceMesh, const int numSubdivisions = 1); + return getOpenEdgeCount(surfMesh) == 0; +} /// -/// \brief Sub-divides an input imstk SurfaceMesh using loop subdivision algorithm -/// Refer <a href="https://vtk.org/doc/nightly/html/classvtkLoopSubdivisionFilter.html#details">vtk loop subdivision</a> -/// for more details +/// \brief Returns volume estimate of closed SurfaceMesh /// -std::unique_ptr<SurfaceMesh> loopSubdivideSurfaceMesh(std::shared_ptr<SurfaceMesh> surfaceMesh, const int numSubdivisions = 1); +double getVolume(std::shared_ptr<SurfaceMesh> surfMesh); /// /// \brief Create a tetrahedral mesh based on a uniform Cartesian mesh diff --git a/Source/GeometryMappers/imstkIsometricMap.h b/Source/GeometryMappers/imstkIsometricMap.h index adf7f454a9527c17a58bc57350751a1c08263818..f097b17fb7d5d9243942cbf249c1168e7b2c6c89 100644 --- a/Source/GeometryMappers/imstkIsometricMap.h +++ b/Source/GeometryMappers/imstkIsometricMap.h @@ -47,7 +47,7 @@ public: /// \brief Constructor /// IsometricMap(std::shared_ptr<Geometry> master, std::shared_ptr<Geometry> slave) : - GeometryMap(GeometryMap::Type::Isometric), + GeometryMap(master, slave, GeometryMap::Type::Isometric), m_rigidTransform(RigidTransform3d::Identity()) {} diff --git a/Source/GeometryMappers/imstkOneToOneMap.cpp b/Source/GeometryMappers/imstkOneToOneMap.cpp index 2a8a92b7ce2b2db342e9445654f18c4b0a70158e..3cc0e056c36f9ffdc24d01e58c5013eb31a6d152 100644 --- a/Source/GeometryMappers/imstkOneToOneMap.cpp +++ b/Source/GeometryMappers/imstkOneToOneMap.cpp @@ -24,10 +24,6 @@ #include "imstkLogger.h" #include "imstkPointSet.h" -#undef min -#undef max -#include <climits> - namespace imstk { void diff --git a/Source/GeometryMappers/imstkOneToOneMap.h b/Source/GeometryMappers/imstkOneToOneMap.h index 8982eb7a48779fef2b895427e4032fe3e12ef2cc..c3e4f507d59b1f5f7b977e5415c9bba9d9bb93a2 100644 --- a/Source/GeometryMappers/imstkOneToOneMap.h +++ b/Source/GeometryMappers/imstkOneToOneMap.h @@ -21,7 +21,6 @@ #pragma once -// imstk #include "imstkGeometryMap.h" namespace imstk diff --git a/Source/GeometryMappers/imstkTetraTriangleMap.cpp b/Source/GeometryMappers/imstkTetraTriangleMap.cpp index b34db1489be385a716ec13373e5d4ce525271b3f..ffbc0e6e4f2db1ab4ab46e537471d48a41cabe9b 100644 --- a/Source/GeometryMappers/imstkTetraTriangleMap.cpp +++ b/Source/GeometryMappers/imstkTetraTriangleMap.cpp @@ -20,9 +20,10 @@ =========================================================================*/ #include "imstkTetraTriangleMap.h" -#include "imstkSurfaceMesh.h" -#include "imstkParallelUtils.h" #include "imstkLogger.h" +#include "imstkParallelUtils.h" +#include "imstkSurfaceMesh.h" +#include "imstkTetrahedralMesh.h" namespace imstk { diff --git a/Source/GeometryMappers/imstkTetraTriangleMap.h b/Source/GeometryMappers/imstkTetraTriangleMap.h index 8a75db015172c551e10cc6739d127e8370f86a28..1d1c3fa438ad24a63f9baed27105282714a96ca2 100644 --- a/Source/GeometryMappers/imstkTetraTriangleMap.h +++ b/Source/GeometryMappers/imstkTetraTriangleMap.h @@ -21,11 +21,8 @@ #pragma once -#include <limits> - -// imstk #include "imstkGeometryMap.h" -#include "imstkTetrahedralMesh.h" +#include <array> namespace imstk { @@ -106,9 +103,9 @@ protected: /// size_t findClosestTetrahedron(const Vec3d& pos) const; - std::vector<TetrahedralMesh::WeightsArray> m_verticesWeights; ///> weights + std::vector<std::array<double, 4>> m_verticesWeights; ///> weights - std::vector<size_t> m_verticesEnclosingTetraId; ///> Enclosing tetrahedra to interpolate the weights upon + std::vector<size_t> m_verticesEnclosingTetraId; ///> Enclosing tetrahedra to interpolate the weights upon std::vector<Vec3d> m_bBoxMin; std::vector<Vec3d> m_bBoxMax; diff --git a/Source/MeshIO/imstkAssimpMeshIO.cpp b/Source/MeshIO/imstkAssimpMeshIO.cpp index 642d604dd8aee4fd8e352455784d6ab6b435e16d..1a2c14e22824cc6b03ede7c96e6b65c88bc90645 100644 --- a/Source/MeshIO/imstkAssimpMeshIO.cpp +++ b/Source/MeshIO/imstkAssimpMeshIO.cpp @@ -21,12 +21,13 @@ #include "imstkAssimpMeshIO.h" #include "imstkLogger.h" +#include "imstkMeshIO.h" +#include "imstkSurfaceMesh.h" -// assimp -#include "assimp/Importer.hpp" -#include "assimp/mesh.h" -#include "assimp/scene.h" -#include "assimp/postprocess.h" +#include <assimp/Importer.hpp> +#include <assimp/mesh.h> +#include <assimp/postprocess.h> +#include <assimp/scene.h> namespace imstk { diff --git a/Source/MeshIO/imstkAssimpMeshIO.h b/Source/MeshIO/imstkAssimpMeshIO.h index c921416be9fc5dd54a77c72ef5bcb1417d9cde27..7b720f72a1d3d3c4ffa0d87ae8e30c2bb3c0c41f 100644 --- a/Source/MeshIO/imstkAssimpMeshIO.h +++ b/Source/MeshIO/imstkAssimpMeshIO.h @@ -21,13 +21,14 @@ #pragma once -#include "imstkSurfaceMesh.h" #include "imstkMeshIO.h" struct aiMesh; namespace imstk { +class SurfaceMesh; + /// /// \class AssimpMeshIO /// diff --git a/Source/MeshIO/imstkMSHMeshIO.cpp b/Source/MeshIO/imstkMSHMeshIO.cpp index aaa879f956e8c18d51db46fcf617b3481a365d0a..f04fde53caf0c880faaf3cdc2d648d97211242c4 100644 --- a/Source/MeshIO/imstkMSHMeshIO.cpp +++ b/Source/MeshIO/imstkMSHMeshIO.cpp @@ -19,19 +19,12 @@ =========================================================================*/ -#include <fstream> -#include <iostream> -#include <algorithm> -#include <array> - #include "imstkMSHMeshIO.h" -#include "imstkTetrahedralMesh.h" #include "imstkHexahedralMesh.h" -#include "imstkVolumetricMesh.h" - -#include "tetMesh.h" - #include "imstkLogger.h" +#include "imstkTetrahedralMesh.h" + +#include <fstream> namespace imstk { diff --git a/Source/MeshIO/imstkMeshIO.cpp b/Source/MeshIO/imstkMeshIO.cpp index 5245897c0764daf0571efd3b2e616ab5d8829c20..7938980bb812787fa2b42000f588ae163be7cf86 100644 --- a/Source/MeshIO/imstkMeshIO.cpp +++ b/Source/MeshIO/imstkMeshIO.cpp @@ -19,21 +19,16 @@ =========================================================================*/ -#include <sys/stat.h> - #include "imstkMeshIO.h" -#include "imstkVTKMeshIO.h" #include "imstkAssimpMeshIO.h" -#include "imstkVegaMeshIO.h" +#include "imstkLogger.h" #include "imstkMSHMeshIO.h" -//#include "imstkColor.h" - #include "imstkSurfaceMesh.h" -#include "imstkLineMesh.h" #include "imstkTetrahedralMesh.h" -#include "imstkHexahedralMesh.h" +#include "imstkVegaMeshIO.h" +#include "imstkVTKMeshIO.h" -#include "imstkLogger.h" +#include <sys/stat.h> namespace imstk { @@ -59,6 +54,7 @@ MeshIO::read(const std::string& filePath) case MeshFileType::STL: case MeshFileType::PLY: case MeshFileType::NRRD: + case MeshFileType::NII: case MeshFileType::DCM: return VTKMeshIO::read(filePath, meshType); break; @@ -166,6 +162,10 @@ MeshIO::getFileType(const std::string& filePath) { meshType = MeshFileType::NRRD; } + else if (extString == "nii" || extString == "NII") + { + meshType = MeshFileType::NII; + } else { LOG(FATAL) << "MeshIO::getFileType error: unknown file extension"; @@ -183,6 +183,8 @@ MeshIO::write(const std::shared_ptr<imstk::PointSet> imstkMesh, const std::strin case MeshFileType::VEG: return VegaMeshIO::write(imstkMesh, filePath, meshType); break; + case MeshFileType::NII: + case MeshFileType::NRRD: case MeshFileType::VTU: case MeshFileType::VTK: case MeshFileType::VTP: diff --git a/Source/MeshIO/imstkMeshIO.h b/Source/MeshIO/imstkMeshIO.h index 7269d1f72f57f4356703074246d27e263932a95c..889ac9de5bf270d9d8b0af2ad44d795cb46640ee 100644 --- a/Source/MeshIO/imstkMeshIO.h +++ b/Source/MeshIO/imstkMeshIO.h @@ -21,11 +21,13 @@ #pragma once -// imstk -#include "imstkPointSet.h" +#include <memory> +#include <string> namespace imstk { +class PointSet; + /// /// \brief Enumeration the mesh file type /// @@ -44,7 +46,8 @@ enum MeshFileType VEG, MSH, NRRD, - DCM + DCM, + NII }; /// @@ -55,7 +58,6 @@ enum MeshFileType class MeshIO { public: - /// /// \brief Constructor /// @@ -71,6 +73,9 @@ public: /// static std::shared_ptr<PointSet> read(const std::string& filePath); + template<typename T> + static std::shared_ptr<T> read(const std::string& filePath) { return std::dynamic_pointer_cast<T>(read(filePath)); } + /// /// \brief Write external file /// diff --git a/Source/MeshIO/imstkVTKMeshIO.cpp b/Source/MeshIO/imstkVTKMeshIO.cpp index 80b1363fe5b821d4fc52665b3a39a7551eae4cf1..2356f502bd41d4231a2cf92171910f1d93ba84d4 100644 --- a/Source/MeshIO/imstkVTKMeshIO.cpp +++ b/Source/MeshIO/imstkVTKMeshIO.cpp @@ -21,32 +21,32 @@ #include "imstkVTKMeshIO.h" #include "imstkGeometryUtilities.h" - -#include "vtkDICOMImageReader.h" -#include "vtkFloatArray.h" -#include "vtkGenericDataObjectReader.h" -#include "vtkGenericDataObjectWriter.h" -#include "vtkNrrdReader.h" -#include "vtkOBJReader.h" -#include "vtkPLYReader.h" -#include "vtkPLYWriter.h" -#include "vtkPolyDataWriter.h" -#include "vtkSmartPointer.h" -#include "vtkSTLReader.h" -#include "vtkSTLWriter.h" -#include "vtkTriangleFilter.h" -#include "vtkXMLPolyDataReader.h" -#include "vtkXMLPolyDataWriter.h" -#include "vtkXMLUnstructuredGridReader.h" -#include "vtkXMLUnstructuredGridWriter.h" - -#include "imstkSurfaceMesh.h" +#include "imstkHexahedralMesh.h" +#include "imstkImageData.h" #include "imstkLineMesh.h" +#include "imstkLogger.h" +#include "imstkSurfaceMesh.h" #include "imstkTetrahedralMesh.h" -#include "imstkHexahedralMesh.h" -//#include "imstkColor.h" -#include "imstkLogger.h" +#include <vtkDICOMImageReader.h> +#include <vtkGenericDataObjectReader.h> +#include <vtkGenericDataObjectWriter.h> +#include <vtkImageData.h> +#include <vtkNIFTIImageReader.h> +#include <vtkNIFTIImageWriter.h> +#include <vtkNrrdReader.h> +#include <vtkOBJReader.h> +#include <vtkPLYReader.h> +#include <vtkPLYWriter.h> +#include <vtkPolyDataWriter.h> +#include <vtkSTLReader.h> +#include <vtkSTLWriter.h> +#include <vtkTriangleFilter.h> +#include <vtkUnstructuredGrid.h> +#include <vtkXMLPolyDataReader.h> +#include <vtkXMLPolyDataWriter.h> +#include <vtkXMLUnstructuredGridReader.h> +#include <vtkXMLUnstructuredGridWriter.h> namespace imstk { @@ -87,6 +87,10 @@ VTKMeshIO::read(const std::string& filePath, MeshFileType meshType) { return VTKMeshIO::readVtkImageData<vtkNrrdReader>(filePath); } + case MeshFileType::NII: + { + return VTKMeshIO::readVtkImageDataNIFTI(filePath); + } default: { LOG(FATAL) << "VTKMeshIO::read error: file type not supported"; @@ -98,7 +102,20 @@ VTKMeshIO::read(const std::string& filePath, MeshFileType meshType) bool VTKMeshIO::write(const std::shared_ptr<PointSet> imstkMesh, const std::string& filePath, const MeshFileType meshType) { - if (auto vMesh = std::dynamic_pointer_cast<VolumetricMesh>(imstkMesh)) + if (auto imgMesh = std::dynamic_pointer_cast<ImageData>(imstkMesh)) + { + switch (meshType) + { + case MeshFileType::NII: + { + return VTKMeshIO::writeVtkImageDataNIFTI(imgMesh, filePath); + } + default: + LOG(WARNING) << "VTKMeshIO::write error: file type not supported for volumetric mesh."; + return false; + } + } + else if (auto vMesh = std::dynamic_pointer_cast<VolumetricMesh>(imstkMesh)) { switch (meshType) { @@ -129,7 +146,6 @@ VTKMeshIO::write(const std::shared_ptr<PointSet> imstkMesh, const std::string& f { return false; } - break; default: LOG(WARNING) << "VTKMeshIO::write error: file type not supported for volumetric mesh."; @@ -194,12 +210,12 @@ VTKMeshIO::readVtkGenericFormatData(const std::string& filePath) if (vtkSmartPointer<vtkPolyData> vtkMesh = reader->GetPolyDataOutput()) { - return GeometryUtils::convertVtkPolyDataToSurfaceMesh(vtkMesh); + return GeometryUtils::copyToSurfaceMesh(vtkMesh); } if (vtkUnstructuredGrid* vtkMesh = reader->GetUnstructuredGridOutput()) { - return GeometryUtils::convertVtkUnstructuredGridToVolumetricMesh(vtkMesh); + return GeometryUtils::copyToVolumetricMesh(vtkMesh); } LOG(FATAL) << "VTKMeshIO::readVtkGenericFormatData error: could not read with VTK reader."; @@ -219,14 +235,34 @@ VTKMeshIO::readVtkPolyData(const std::string& filePath) triFilter->Update(); vtkSmartPointer<vtkPolyData> vtkMesh = triFilter->GetOutput(); - return GeometryUtils::convertVtkPolyDataToSurfaceMesh(vtkMesh); + return GeometryUtils::copyToSurfaceMesh(vtkMesh); +} + +template<typename WriterType> +bool +VTKMeshIO::writeVtkImageData(const std::shared_ptr<ImageData> imstkMesh, const std::string& filePath) +{ + vtkSmartPointer<vtkImageData> vtkMesh = GeometryUtils::copyToVtkImageData(imstkMesh); + if (!vtkMesh) + { + return false; + } + + int* dim = vtkMesh->GetDimensions(); + auto writer = vtkSmartPointer<WriterType>::New(); + writer->SetFileDimensionality(3); + writer->SetInputData(vtkMesh); + writer->SetFileName(filePath.c_str()); + writer->Write(); + + return true; } template<typename WriterType> bool VTKMeshIO::writeVtkPolyData(std::shared_ptr<SurfaceMesh> imstkMesh, const std::string& filePath) { - vtkSmartPointer<vtkPolyData> vtkMesh = GeometryUtils::convertSurfaceMeshToVtkPolyData(imstkMesh); + vtkSmartPointer<vtkPolyData> vtkMesh = GeometryUtils::copyToVtkPolyData(imstkMesh); if (!vtkMesh) { return false; @@ -244,7 +280,7 @@ template<typename WriterType> bool VTKMeshIO::writeVtkPolyData(std::shared_ptr<LineMesh> imstkMesh, const std::string& filePath) { - vtkSmartPointer<vtkPolyData> vtkMesh = GeometryUtils::convertLineMeshToVtkPolyData(imstkMesh); + vtkSmartPointer<vtkPolyData> vtkMesh = GeometryUtils::copyToVtkPolyData(imstkMesh); if (!vtkMesh) { return false; @@ -262,7 +298,7 @@ template<typename WriterType> bool VTKMeshIO::writeVtkPointSet(const std::shared_ptr<PointSet> imstkMesh, const std::string& filePath) { - vtkSmartPointer<vtkPointSet> vtkMesh = GeometryUtils::convertPointSetToVtkPointSet(imstkMesh); + vtkSmartPointer<vtkPointSet> vtkMesh = GeometryUtils::copyToVtkPointSet(imstkMesh); if (!vtkMesh) { return false; @@ -285,20 +321,7 @@ VTKMeshIO::readVtkUnstructuredGrid(const std::string& filePath) reader->Update(); vtkSmartPointer<vtkUnstructuredGrid> vtkMesh = reader->GetOutput(); - return GeometryUtils::convertVtkUnstructuredGridToVolumetricMesh(vtkMesh); -} - -template<typename ReaderType> -std::shared_ptr<ImageData> -VTKMeshIO::readVtkImageData(const std::string& filePath) -{ - auto reader = vtkSmartPointer<ReaderType>::New(); - reader->SetFileName(filePath.c_str()); - reader->Update(); - - auto imageData = std::make_shared<ImageData>(); - imageData->initialize(reader->GetOutput()); - return imageData; + return GeometryUtils::copyToVolumetricMesh(vtkMesh); } std::shared_ptr<ImageData> @@ -317,8 +340,8 @@ VTKMeshIO::readVtkImageDataDICOM(const std::string& filePath) reader->SetDirectoryName(filePath.c_str()); reader->Update(); - auto imageData = std::make_shared<ImageData>(); - imageData->initialize(reader->GetOutput()); + std::shared_ptr<ImageData> imageData( + std::move(GeometryUtils::copyToImageData(reader->GetOutput()))); return imageData; } @@ -326,7 +349,7 @@ template<typename WriterType> bool VTKMeshIO::writeVtkUnstructuredGrid(std::shared_ptr<TetrahedralMesh> tetMesh, const std::string& filePath) { - auto vtkMesh = GeometryUtils::convertTetrahedralMeshToVtkUnstructuredGrid(tetMesh); + auto vtkMesh = GeometryUtils::copyToVtkUnstructuredGrid(tetMesh); if (!vtkMesh) { @@ -346,7 +369,7 @@ template<typename WriterType> bool VTKMeshIO::writeVtkUnstructuredGrid(std::shared_ptr<HexahedralMesh> hMesh, const std::string& filePath) { - auto vtkMesh = GeometryUtils::convertHexahedralMeshToVtkUnstructuredGrid(hMesh); + auto vtkMesh = GeometryUtils::copyToVtkUnstructuredGrid(hMesh); if (!vtkMesh) { @@ -361,4 +384,56 @@ VTKMeshIO::writeVtkUnstructuredGrid(std::shared_ptr<HexahedralMesh> hMesh, const return true; } + +/// +/// \brief Reads vtk image data +/// +template<typename ReaderType> +std::shared_ptr<ImageData> +VTKMeshIO::readVtkImageData(const std::string& filePath) +{ + auto reader = vtkSmartPointer<ReaderType>::New(); + reader->SetFileName(filePath.c_str()); + reader->Update(); + + std::shared_ptr<ImageData> imageData(std::move(GeometryUtils::copyToImageData(reader->GetOutput()))); + return imageData; +} + +/// +/// \brief Reads nifti/nii format image data +/// +std::shared_ptr<ImageData> +VTKMeshIO::readVtkImageDataNIFTI(const std::string& filePath) +{ + auto reader = vtkSmartPointer<vtkNIFTIImageReader>::New(); + reader->SetFileName(filePath.c_str()); + reader->SetFileDimensionality(3); + reader->Update(); + + std::shared_ptr<ImageData> imageData(std::move(GeometryUtils::copyToImageData(reader->GetOutput()))); + return imageData; +} + +/// +/// \brief Write nifti/nii format image data +/// +bool +VTKMeshIO::writeVtkImageDataNIFTI(std::shared_ptr<ImageData> imageData, const std::string& filePath) +{ + // Copy instead of couple for thread safety + auto vtkMesh = GeometryUtils::copyToVtkImageData(imageData); + if (!vtkMesh) + { + LOG(WARNING) << "VTKMeshIO::writeVtkImageDataNIFTI error: conversion unsuccessful"; + return false; + } + + auto writer = vtkSmartPointer<vtkNIFTIImageWriter>::New(); + writer->SetFileName(filePath.c_str()); + writer->SetFileDimensionality(3); + writer->SetInputData(vtkMesh); + writer->Update(); + return true; +} } // imstk diff --git a/Source/MeshIO/imstkVTKMeshIO.h b/Source/MeshIO/imstkVTKMeshIO.h index 08d53279b01139c19e23ff9d77e2d0bdae4e115f..92dbafda083db45a22578d26af6d9a24ba05707f 100644 --- a/Source/MeshIO/imstkVTKMeshIO.h +++ b/Source/MeshIO/imstkVTKMeshIO.h @@ -21,24 +21,17 @@ #pragma once -#include <memory> - -#include "vtkUnstructuredGrid.h" -#include "vtkPolyData.h" -#include "vtkPoints.h" -#include "vtkCellArray.h" -#include "vtkPointData.h" - #include "imstkMeshIO.h" -#include "imstkImageData.h" namespace imstk { -class SurfaceMesh; +class HexahedralMesh; +class ImageData; class LineMesh; +class SurfaceMesh; class TetrahedralMesh; -class HexahedralMesh; class VolumetricMesh; + /// /// \class VTKMeshIO /// @@ -82,6 +75,12 @@ protected: template<typename ReaderType> static std::shared_ptr<SurfaceMesh> readVtkPolyData(const std::string& filePath); + /// + /// \brief Writes the given image data to given file path using the provided writer type + /// + template<typename WriterType> + static bool writeVtkImageData(const std::shared_ptr<ImageData> imstkMesh, const std::string& filePath); + /// /// \brief Writes the given surface mesh to given file path using the provided writer type /// @@ -124,5 +123,15 @@ protected: /// \brief TODO /// static std::shared_ptr<ImageData> readVtkImageDataDICOM(const std::string& filePath); + + /// + /// \brief Reads nifti/nii format image data + /// + static std::shared_ptr<ImageData> readVtkImageDataNIFTI(const std::string& filePath); + + /// + /// \brief Write nifti/nii format image data + /// + static bool writeVtkImageDataNIFTI(std::shared_ptr<ImageData> imageData, const std::string& filePath); }; } // imstk diff --git a/Source/MeshIO/imstkVegaMeshIO.cpp b/Source/MeshIO/imstkVegaMeshIO.cpp index 98a61e6f3e72dc0847740115163438cdfd751bc9..1a6378e010dae82d4810e264df53d7a121c843e2 100644 --- a/Source/MeshIO/imstkVegaMeshIO.cpp +++ b/Source/MeshIO/imstkVegaMeshIO.cpp @@ -20,20 +20,12 @@ =========================================================================*/ #include "imstkVegaMeshIO.h" -#include "imstkMeshIO.h" -#include "imstkTetrahedralMesh.h" #include "imstkHexahedralMesh.h" -#include "imstkVolumetricMesh.h" - #include "imstkLogger.h" +#include "imstkTetrahedralMesh.h" -// Vega -#include "volumetricMeshLoader.h" -#include "volumetricMesh.h" - -#include "tetMesh.h" - -#include <array> +#include <tetMesh.h> +#include <volumetricMeshLoader.h> namespace imstk { diff --git a/Source/MeshIO/imstkVegaMeshIO.h b/Source/MeshIO/imstkVegaMeshIO.h index 8e53f8d8c2e2ee2830fe83f55f14c1ce4e422605..ce72784a6fde14598b24f52b2fd8ca3ceddc6d5a 100644 --- a/Source/MeshIO/imstkVegaMeshIO.h +++ b/Source/MeshIO/imstkVegaMeshIO.h @@ -21,6 +21,7 @@ #pragma once +#include "imstkMath.h" #include "imstkMeshIO.h" namespace vega diff --git a/Source/Rendering/CMakeLists.txt b/Source/Rendering/CMakeLists.txt index 52326e9f6b34ee402083b3232cf2c138efc7b713..36387f380b457a8d4f3d73c04f339ab1b391577d 100644 --- a/Source/Rendering/CMakeLists.txt +++ b/Source/Rendering/CMakeLists.txt @@ -20,7 +20,7 @@ set(VTK_H_FILES VTKRenderer/RenderDelegate/imstkVTKdebugLinesRenderDelegate.h VTKRenderer/RenderDelegate/imstkVTKdebugPointsRenderDelegate.h VTKRenderer/RenderDelegate/imstkVTKPointSetRenderDelegate.h - VTKRenderer/RenderDelegate/imstkVTKFluidRenderDelegate.h) + VTKRenderer/RenderDelegate/imstkVTKFluidRenderDelegate.h) set(VTK_CPP_FILES VTKRenderer/imstkVTKRenderer.cpp @@ -96,10 +96,8 @@ if( NOT iMSTK_USE_Vulkan ) VTKRenderer/RenderDelegate) set(RENDERING_DEPENDENCIES #GUIOverlay - Materials) - if (iMSTK_ENABLE_VR) - list(APPEND RENDERING_DEPENDENCIES openvr) - endif() + Materials + openvr) else() set(RENDERING_H_FILES ${VULKAN_H_FILES}) set(RENDERING_CPP_FILES ${VULKAN_CPP_FILES}) @@ -109,7 +107,8 @@ else() VulkanRenderer/PostProcessing) set(RENDERING_DEPENDENCIES GUIOverlay - Materials) + Materials + openvr) set(RENDERING_LIBRARIES ${Vulkan} glfw @@ -122,7 +121,6 @@ imstk_add_library( Rendering imstkRenderer.h ${RENDERING_H_FILES} CPP_FILES - imstkRenderer.cpp ${RENDERING_CPP_FILES} SUBDIR_LIST ${RENDERING_SUBDIR} diff --git a/Source/Rendering/Materials/imstkRenderMaterial.cpp b/Source/Rendering/Materials/imstkRenderMaterial.cpp index 63bedfd6292b7d239b2b06534a35f4b5c32a43a8..a5def361aa3c5a3cb45af85a502e23c020184fbf 100644 --- a/Source/Rendering/Materials/imstkRenderMaterial.cpp +++ b/Source/Rendering/Materials/imstkRenderMaterial.cpp @@ -20,7 +20,7 @@ =========================================================================*/ #include "imstkRenderMaterial.h" -#include "imstkTexture.h" +#include "imstkLogger.h" namespace imstk { diff --git a/Source/Rendering/Materials/imstkRenderMaterial.h b/Source/Rendering/Materials/imstkRenderMaterial.h index 7dae67f758dfb0ea52c9ff2730a66f42fbc4b792..a479958016126892dd10050d66756750a9cea374 100644 --- a/Source/Rendering/Materials/imstkRenderMaterial.h +++ b/Source/Rendering/Materials/imstkRenderMaterial.h @@ -22,7 +22,9 @@ #pragma once #include "imstkColor.h" -#include "imstkTextureManager.h" +#include "imstkTexture.h" + +#include <vector> namespace imstk { @@ -44,7 +46,8 @@ public: Points, WireframeSurface, VolumeRendering, - Fluid ///< Renders a set of points using a screen-space fluid renderer + Fluid, ///< Renders a set of points using a screen-space fluid renderer + Image }; /// surface shading model. Defaults to Phong @@ -65,11 +68,11 @@ public: MinimumIntensity }; - /// - /// \brief Constructor - /// +public: RenderMaterial(); + virtual ~RenderMaterial() = default; +public: /// /// \brief Get/Set display mode /// @@ -89,9 +92,12 @@ public: void setLineWidth(const float width); /// - /// \brief Get/Set point size + /// \brief Get/Set point radius /// float getPointSize() const; + /// + /// \brief Get/Set point radius + /// void setPointSize(const float size); /// diff --git a/Source/Rendering/Materials/imstkTexture.h b/Source/Rendering/Materials/imstkTexture.h index 19ec07e6a925afdc4e4654e486fd7ff15528e23a..9b6942838d654d61a1d71ad2ca7068772fdebffd 100644 --- a/Source/Rendering/Materials/imstkTexture.h +++ b/Source/Rendering/Materials/imstkTexture.h @@ -24,8 +24,6 @@ #include <string> #include <memory> -#include "imstkLogger.h" - namespace imstk { /// @@ -77,7 +75,7 @@ public: /// /// \brief Destructor /// - virtual ~Texture() {} + virtual ~Texture() = default; /// /// \brief Get type diff --git a/Source/Rendering/Materials/imstkTextureDelegate.h b/Source/Rendering/Materials/imstkTextureDelegate.h index 62440771dc4071628ddc02ee66aa9a084d01949e..15b93eb4dd2b1f9aa438f2eabcbaca6ca71e77c1 100644 --- a/Source/Rendering/Materials/imstkTextureDelegate.h +++ b/Source/Rendering/Materials/imstkTextureDelegate.h @@ -21,10 +21,12 @@ #pragma once -#include "imstkTexture.h" +#include <memory> namespace imstk { +class Texture; + /// /// \class TextureDelegate /// @@ -32,12 +34,15 @@ namespace imstk /// class TextureDelegate { +public: + virtual ~TextureDelegate() = default; + protected: /// /// \brief Constructor /// \param texture The texture /// - TextureDelegate() {} + TextureDelegate() { } /// /// \brief Abstract function to load textures diff --git a/Source/Rendering/Materials/imstkTextureManager.h b/Source/Rendering/Materials/imstkTextureManager.h index 01c0fde8bb3e621f74f9fda539ff75cd90e1d2fa..af367581c1373b9d0816d809902a6d182b6295b8 100644 --- a/Source/Rendering/Materials/imstkTextureManager.h +++ b/Source/Rendering/Materials/imstkTextureManager.h @@ -24,6 +24,8 @@ #include "imstkTexture.h" #include "imstkTextureDelegate.h" +#include <map> + namespace imstk { template<class T> @@ -43,7 +45,7 @@ protected: /// /// \brief Constructor /// - TextureManager() {} + TextureManager() = default; std::map<std::shared_ptr<Texture>, std::shared_ptr<T>> m_textureMap; }; diff --git a/Source/Rendering/Materials/imstkVolumeRenderMaterial.cpp b/Source/Rendering/Materials/imstkVolumeRenderMaterial.cpp index 57d30a1f11f1af586b29acd1334f1073f2273828..23670d98dd106d6a8245032371935ae25eb3a16a 100644 --- a/Source/Rendering/Materials/imstkVolumeRenderMaterial.cpp +++ b/Source/Rendering/Materials/imstkVolumeRenderMaterial.cpp @@ -21,12 +21,15 @@ #include "imstkVolumeRenderMaterial.h" -// imstk #include <vtkVolumeProperty.h> namespace imstk { -vtkVolumeProperty* +VolumeRenderMaterial::VolumeRenderMaterial() : m_property(vtkSmartPointer<vtkVolumeProperty>::New()) +{ +} + +vtkSmartPointer<vtkVolumeProperty> VolumeRenderMaterial::getVolumeProperty() { return this->m_property; diff --git a/Source/Rendering/Materials/imstkVolumeRenderMaterial.h b/Source/Rendering/Materials/imstkVolumeRenderMaterial.h index e2c6d7f519620644d9782871c8bb9e2915c9e735..fb61676b4a8ba90c4adf157edf8c3fc24056672d 100644 --- a/Source/Rendering/Materials/imstkVolumeRenderMaterial.h +++ b/Source/Rendering/Materials/imstkVolumeRenderMaterial.h @@ -21,26 +21,27 @@ #pragma once -// imstk #include "imstkRenderMaterial.h" -// vtk -#include <vtkNew.h> +#include <vtkSmartPointer.h> -// forward declarations class vtkVolumeProperty; namespace imstk { class VolumeRenderMaterial : public RenderMaterial { +public: + VolumeRenderMaterial(); + ~VolumeRenderMaterial() override = default; + public: /// - /// \brief Set/Get the volume property + /// \brief Get the volume property /// - vtkVolumeProperty* getVolumeProperty(); + vtkSmartPointer<vtkVolumeProperty> getVolumeProperty(); protected: - vtkNew<vtkVolumeProperty> m_property; + vtkSmartPointer<vtkVolumeProperty> m_property; }; } diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCapsuleRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCapsuleRenderDelegate.cpp index 6b272614f57f0814426b433e216271410f1fe4eb..260b339113d22bbd1352ce848537a218848ea301 100644 --- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCapsuleRenderDelegate.cpp +++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCapsuleRenderDelegate.cpp @@ -21,7 +21,10 @@ #include "imstkVTKCapsuleRenderDelegate.h" #include "imstkCapsule.h" +#include "imstkVisualModel.h" + #include <vtkCapsuleSource.h> +#include <vtkTransform.h> #include <vtkTransformPolyDataFilter.h> namespace imstk diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCapsuleRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCapsuleRenderDelegate.h index 16f192958f7e1717195bd4bc8ffd822b08d58a45..f1c15f5b551306ca36ffb846842da970f42b2f68 100644 --- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCapsuleRenderDelegate.h +++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCapsuleRenderDelegate.h @@ -43,7 +43,7 @@ public: /// /// \brief destructor /// - ~VTKCapsuleRenderDelegate() = default; + virtual ~VTKCapsuleRenderDelegate() override = default; /// /// \brief Update capsule source based on the capsule geometry diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCubeRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCubeRenderDelegate.cpp index 2ca51a5a5f6bb5d65897d0c32e6a514da2879939..6a5ba86c207fd488dcaea8a20fa91dc7515e61bc 100644 --- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCubeRenderDelegate.cpp +++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCubeRenderDelegate.cpp @@ -21,9 +21,11 @@ #include "imstkVTKCubeRenderDelegate.h" #include "imstkCube.h" +#include "imstkVisualModel.h" -#include "vtkTransformPolyDataFilter.h" -#include "vtkCubeSource.h" +#include <vtkCubeSource.h> +#include <vtkTransform.h> +#include <vtkTransformPolyDataFilter.h> namespace imstk { diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCubeRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCubeRenderDelegate.h index 9b43993fe10699ee78b5755eef14760bb4d9593a..95b5da6803119bd8930ed03e71a0c8cf6a026545 100644 --- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCubeRenderDelegate.h +++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCubeRenderDelegate.h @@ -43,7 +43,7 @@ public: /// /// \brief Destructor /// - ~VTKCubeRenderDelegate() = default; + virtual ~VTKCubeRenderDelegate() override = default; /// /// \brief Update cube source based on the cube geometry diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCylinderRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCylinderRenderDelegate.cpp index c438c8c784bbd0868cfc7c771ae4b3b20cab1618..d0a1f16f4adbf1d14984f1f6a8e8a75e1882af99 100644 --- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCylinderRenderDelegate.cpp +++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCylinderRenderDelegate.cpp @@ -21,9 +21,11 @@ #include "imstkVTKCylinderRenderDelegate.h" #include "imstkCylinder.h" +#include "imstkVisualModel.h" -#include <vtkTransformPolyDataFilter.h> #include <vtkCylinderSource.h> +#include <vtkTransform.h> +#include <vtkTransformPolyDataFilter.h> namespace imstk { diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCylinderRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCylinderRenderDelegate.h index 97cb70ca671ab412f8a0afc211f723eb91052547..9e6ca1cba5c539b49bf5847fda00190413f956a7 100644 --- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCylinderRenderDelegate.h +++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCylinderRenderDelegate.h @@ -44,7 +44,7 @@ public: /// /// \brief Destructor /// - ~VTKCylinderRenderDelegate() = default; + virtual ~VTKCylinderRenderDelegate() override = default; /// /// \brief Update cylinder source based on the cylinder geometry diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKFluidRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKFluidRenderDelegate.cpp index 077c6721bd820e18ebbcfb814ea2b136bddb5cdb..9f7b2f1ae98be74ae9cc5387f12bf783e9693846 100644 --- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKFluidRenderDelegate.cpp +++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKFluidRenderDelegate.cpp @@ -21,15 +21,13 @@ #include "imstkVTKFluidRenderDelegate.h" #include "imstkPointSet.h" +#include "imstkVisualModel.h" +#include "imstkRenderMaterial.h" -#include <vtkOpenGLPolyDataMapper.h> #include <vtkOpenGLFluidMapper.h> #include <vtkVertexGlyphFilter.h> #include <vtkTrivialProducer.h> -#include <vtkSphereSource.h> #include <vtkDoubleArray.h> -#include <vtkGlyph3D.h> -#include <vtkVersion.h> #include <vtkVolume.h> namespace imstk @@ -61,18 +59,18 @@ VTKFluidRenderDelegate::VTKFluidRenderDelegate(std::shared_ptr<VisualModel> visu fluidMapper->SetInputData(pointsPolydata); // set some fluid rendering properties - fluidMapper->SetParticleRadius(0.03f * 6.0f); + fluidMapper->SetParticleRadius(m_visualModel->getRenderMaterial()->getPointSize()); fluidMapper->SetSurfaceFilterIterations(3); fluidMapper->SetSurfaceFilterRadius(5); fluidMapper->SetSurfaceFilterMethod(vtkOpenGLFluidMapper::FluidSurfaceFilterMethod::NarrowRange); fluidMapper->SetDisplayMode(vtkOpenGLFluidMapper::FluidDisplayMode::TransparentFluidVolume); - fluidMapper->SetAttenuationColor(0.8f, 0.2f, 0.15f); - fluidMapper->SetAttenuationScale(1.0f); - fluidMapper->SetOpaqueColor(0.0f, 0.0f, 0.9f); + fluidMapper->SetAttenuationColor(0.1f, 0.9f, 0.9f); + fluidMapper->SetAttenuationScale(16.0f); + fluidMapper->SetOpaqueColor(0.9f, 0.1f, 0.1f); fluidMapper->SetParticleColorPower(0.1f); fluidMapper->SetParticleColorScale(0.57f); fluidMapper->SetAdditionalReflection(0.0f); - fluidMapper->SetRefractiveIndex(1.33f); + fluidMapper->SetRefractiveIndex(1.5f); fluidMapper->SetRefractionScale(0.07f); m_volume->SetMapper(fluidMapper); diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKFluidRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKFluidRenderDelegate.h index 6cb2fd54416547a87ae04df1d4279e71beb9690d..d673e0a2dcd64e2c8e6c0ee46498ce599ba3b88d 100644 --- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKFluidRenderDelegate.h +++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKFluidRenderDelegate.h @@ -45,7 +45,7 @@ public: /// /// \brief Destructor /// - ~VTKFluidRenderDelegate() = default; + virtual ~VTKFluidRenderDelegate() override = default; /// /// \brief Update polydata source based on the mesh geometry diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKHexahedralMeshRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKHexahedralMeshRenderDelegate.cpp index 2f8b69cdd1d5b60bd04641455fca7f8288d20700..d2a603855e026b8b62c38d619b7761316df64c38 100644 --- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKHexahedralMeshRenderDelegate.cpp +++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKHexahedralMeshRenderDelegate.cpp @@ -21,13 +21,12 @@ #include "imstkVTKHexahedralMeshRenderDelegate.h" #include "imstkHexahedralMesh.h" +#include "imstkVisualModel.h" -#include <vtkUnstructuredGrid.h> +#include <vtkActor.h> #include <vtkDataSetMapper.h> #include <vtkDoubleArray.h> -#include <vtkCellArray.h> -#include <vtkProperty.h> -#include <vtkPoints.h> +#include <vtkUnstructuredGrid.h> #include <array> diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKHexahedralMeshRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKHexahedralMeshRenderDelegate.h index 3ef1e9eeb673d84fd47903c93976bd83334bb2ba..2dca4112d6d3174dfd9261bbc0097d44c9adc54f 100644 --- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKHexahedralMeshRenderDelegate.h +++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKHexahedralMeshRenderDelegate.h @@ -45,7 +45,7 @@ public: /// /// \brief Destructor /// - ~VTKHexahedralMeshRenderDelegate() = default; + virtual ~VTKHexahedralMeshRenderDelegate() override = default; /// /// \brief Update unstructured grid source based on the hexahedral mesh diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKImageDataRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKImageDataRenderDelegate.cpp index e74d0266953a31a42d527978c4b078e122c33abe..134459f13bd17a2a98f94e234c6f835b9320c376 100644 --- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKImageDataRenderDelegate.cpp +++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKImageDataRenderDelegate.cpp @@ -20,15 +20,16 @@ =========================================================================*/ #include "imstkVTKImageDataRenderDelegate.h" -#include "imstkVolumeRenderMaterial.h" +#include "imstkGeometryUtilities.h" #include "imstkImageData.h" +#include "imstkVisualModel.h" +#include "imstkDataArray.h" #include <vtkGPUVolumeRayCastMapper.h> -#include <vtkColorTransferFunction.h> -#include <vtkPiecewiseFunction.h> -#include <vtkTrivialProducer.h> -#include <vtkVolumeProperty.h> #include <vtkImageData.h> +#include <vtkTrivialProducer.h> +#include <vtkPointData.h> +#include <vtkDataArray.h> namespace imstk { @@ -38,28 +39,64 @@ VTKImageDataRenderDelegate::VTKImageDataRenderDelegate(std::shared_ptr<VisualMod m_isMesh = false; m_modelIsVolume = true; - auto imageData = std::static_pointer_cast<ImageData>(m_visualModel->getGeometry()); - if (imageData->getData()) - { - auto tp = vtkSmartPointer<vtkTrivialProducer>::New(); - tp->SetOutput(imageData->getData()); - this->setUpMapper(tp->GetOutputPort(), m_visualModel); + auto imageData = std::dynamic_pointer_cast<ImageData>(m_visualModel->getGeometry()); + m_scalarArray = imageData->getScalars(); - this->updateActorPropertiesVolumeRendering();// check if this is needed once more! - } + // Couple the imstkImageData with vtkImageData + imageDataVtk = GeometryUtils::coupleVtkImageData(imageData); + + vtkNew<vtkTrivialProducer> tp; + tp->SetOutput(imageDataVtk); + this->setUpMapper(tp->GetOutputPort(), m_visualModel); + + this->updateActorPropertiesVolumeRendering(); // check if this is needed once more! + + // When image is modified, queue an event to this object that calls imageDataModified + queueConnect<Event>(imageData, EventType::Modified, this, &VTKImageDataRenderDelegate::imageDataModified); } void VTKImageDataRenderDelegate::updateDataSource() { + // Handle any queued events + // \todo: Eventually move this to renderdelegate base class + doLastEvent(); +} + +void +VTKImageDataRenderDelegate::imageDataModified(Event* imstkNotUsed(e)) +{ + // Here we utilize something similar to double buffering + // We primarily use a single shared buffer until the moment + // it is reallocated auto imageData = std::static_pointer_cast<ImageData>(m_visualModel->getGeometry()); - if (!imageData->m_dataModified) + // If our handle is not up to date, update it + if (m_scalarArray != imageData->getScalars()) { - return; + // Update our handle + m_scalarArray = imageData->getScalars(); + + // Update vtk data array pointer to this new handle, this will cause existing array to deallocate assuming no + // one else is referencing it + imageDataVtk->GetPointData()->GetScalars()->SetVoidArray(m_scalarArray->getVoidPointer(), m_scalarArray->size(), 1); + + // Update information (currently can't handle type changes or number of components) + const Vec3i& dim = imageData->getDimensions(); + imageDataVtk->SetDimensions(dim.data()); + imageDataVtk->SetExtent(0, dim[0] - 1, 0, dim[1] - 1, 0, dim[2] - 1); + const Vec3d vtkOrigin = imageData->getOrigin() + imageData->getSpacing() * 0.5; + imageDataVtk->SetOrigin(vtkOrigin.data()); + imageDataVtk->SetSpacing(imageData->getSpacing().data()); } - // TODO: Any transforms/modifications? - imageData->m_dataModified = false; + // Always post modified on VTK data, when modified is recieved + m_volumeMapper->GetInput()->Modified(); + + // \todo: transforms + if (imageData->m_transformModified) + { + imageData->m_transformModified = false; + } } } // imstk diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKImageDataRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKImageDataRenderDelegate.h index 710f7c525acf5f358c535be1fae23382f1c7c9aa..4ea6e363ea09109e5fa4f7e63bc9440369e74240 100644 --- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKImageDataRenderDelegate.h +++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKImageDataRenderDelegate.h @@ -23,9 +23,11 @@ #include "imstkVTKRenderDelegate.h" +class vtkImageData; + namespace imstk { -class ImageData; +class AbstractDataArray; /// /// \class VTKImageDataRenderDelegate @@ -43,11 +45,18 @@ public: /// /// \brief Destructor /// - ~VTKImageDataRenderDelegate() = default; + virtual ~VTKImageDataRenderDelegate() override = default; +public: /// /// \brief Update render delegate source based on the internal data /// void updateDataSource() override; + + void imageDataModified(Event* e); + +protected: + std::shared_ptr<AbstractDataArray> m_scalarArray; + vtkSmartPointer<vtkImageData> imageDataVtk; }; } // imstk diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKLineMeshRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKLineMeshRenderDelegate.cpp index 2b5711c251eb0bd780884792d9b99f0a507f138b..3bc430b9e685bbba249cea1570da89a3d98d9aae 100644 --- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKLineMeshRenderDelegate.cpp +++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKLineMeshRenderDelegate.cpp @@ -21,18 +21,12 @@ #include "imstkVTKLineMeshRenderDelegate.h" #include "imstkLineMesh.h" +#include "imstkVisualModel.h" -#include <vtkUnsignedCharArray.h> -#include <vtkTrivialProducer.h> -#include <vtkPolyDataMapper.h> #include <vtkDoubleArray.h> -#include <vtkFloatArray.h> -#include <vtkLineSource.h> -#include <vtkPointData.h> -#include <vtkCellData.h> -#include <vtkPolyData.h> -#include <vtkPoints.h> #include <vtkLine.h> +#include <vtkLineSource.h> +#include <vtkTrivialProducer.h> namespace imstk { diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKLineMeshRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKLineMeshRenderDelegate.h index 6edc6691e5291cef3cbdc662ace87526bc56bf72..ebe334e20406be1284bfa4d19e035308b61d40dd 100644 --- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKLineMeshRenderDelegate.h +++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKLineMeshRenderDelegate.h @@ -42,6 +42,8 @@ public: /// explicit VTKLineMeshRenderDelegate(std::shared_ptr<VisualModel> visualModel); + virtual ~VTKLineMeshRenderDelegate() override = default; + /// /// \brief Update line source based on the line mesh /// diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPlaneRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPlaneRenderDelegate.cpp index 9bb2022a183f12bf8a34af114c96b59386b34a48..5c28d9fb4a777ffc6a16b0bda288460acd1fcded 100644 --- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPlaneRenderDelegate.cpp +++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPlaneRenderDelegate.cpp @@ -21,9 +21,11 @@ #include "imstkVTKPlaneRenderDelegate.h" #include "imstkPlane.h" +#include "imstkVisualModel.h" -#include <vtkTransformPolyDataFilter.h> #include <vtkPlaneSource.h> +#include <vtkTransform.h> +#include <vtkTransformPolyDataFilter.h> namespace imstk { diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPlaneRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPlaneRenderDelegate.h index 2a7c252c1daad17eb7008047aa7694a28bb4bea8..d17422df97cc829904d44cd0257332ab5f3a60c6 100644 --- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPlaneRenderDelegate.h +++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPlaneRenderDelegate.h @@ -45,7 +45,7 @@ public: /// /// \brief Destructor /// - ~VTKPlaneRenderDelegate() = default; + virtual ~VTKPlaneRenderDelegate() override = default; /// /// \brief Update plane source based on the plane geometry diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPointSetRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPointSetRenderDelegate.cpp index 7f42f69982d92f090d604db744986c45fe8c0cc0..43cfabf34e1ff2fa62459370a035b2454cb49f86 100644 --- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPointSetRenderDelegate.cpp +++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPointSetRenderDelegate.cpp @@ -21,15 +21,16 @@ #include "imstkVTKPointSetRenderDelegate.h" #include "imstkPointSet.h" +#include "imstkVisualModel.h" -#include <vtkOpenGLPolyDataMapper.h> -#include <vtkVertexGlyphFilter.h> -#include <vtkTrivialProducer.h> -#include <vtkSphereSource.h> #include <vtkDoubleArray.h> #include <vtkPointData.h> #include <vtkGlyph3D.h> +#include <vtkOpenGLPolyDataMapper.h> +#include <vtkSphereSource.h> +#include <vtkTrivialProducer.h> #include <vtkVersion.h> +#include <vtkVertexGlyphFilter.h> namespace imstk { diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPointSetRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPointSetRenderDelegate.h index 6adafff6c087fa21620efe54761d913c78f014be..15813dde415244cee7bde9f4d7c7a36f461657ad 100644 --- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPointSetRenderDelegate.h +++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPointSetRenderDelegate.h @@ -46,7 +46,7 @@ public: /// /// \brief Destructor /// - ~VTKPointSetRenderDelegate() = default; + virtual ~VTKPointSetRenderDelegate() override = default; /// /// \brief Update polydata source based on the mesh geometry diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKRenderDelegate.cpp index 999a091d8bd02a29bc1fbad1cf917cde43091cb9..01562d1cd168b7aab04033390d3e33fa290a09d4 100644 --- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKRenderDelegate.cpp +++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKRenderDelegate.cpp @@ -20,57 +20,65 @@ =========================================================================*/ #include "imstkVTKRenderDelegate.h" - +#include "imstkDebugRenderGeometry.h" +#include "imstkGeometry.h" #include "imstkLogger.h" +#include "imstkVisualModel.h" +#include "imstkVolumeRenderMaterial.h" -#include "imstkPlane.h" -#include "imstkSphere.h" -#include "imstkCapsule.h" -#include "imstkCylinder.h" -#include "imstkCube.h" -#include "imstkPointSet.h" -#include "imstkSurfaceMesh.h" -#include "imstkLineMesh.h" -#include "imstkTetrahedralMesh.h" -#include "imstkHexahedralMesh.h" -#include "imstkVTKdebugTrianglesRenderDelegate.h" +// Debug render delegates #include "imstkVTKdebugLinesRenderDelegate.h" #include "imstkVTKdebugPointsRenderDelegate.h" -#include "imstkVolumeRenderMaterial.h" +#include "imstkVTKdebugTrianglesRenderDelegate.h" #include "imstkColorFunction.h" // VTK render delegates -#include "imstkVTKTetrahedralMeshRenderDelegate.h" +#include "imstkVTKCapsuleRenderDelegate.h" +#include "imstkVTKCubeRenderDelegate.h" +#include "imstkVTKCylinderRenderDelegate.h" +#include "imstkVTKFluidRenderDelegate.h" #include "imstkVTKHexahedralMeshRenderDelegate.h" -#include "imstkVTKSurfaceMeshRenderDelegate.h" #include "imstkVTKImageDataRenderDelegate.h" #include "imstkVTKLineMeshRenderDelegate.h" -#include "imstkVTKCylinderRenderDelegate.h" +#include "imstkVTKPlaneRenderDelegate.h" #include "imstkVTKPointSetRenderDelegate.h" -#include "imstkVTKCapsuleRenderDelegate.h" #include "imstkVTKSphereRenderDelegate.h" -#include "imstkVTKPlaneRenderDelegate.h" -#include "imstkVTKFluidRenderDelegate.h" -#include "imstkVTKCubeRenderDelegate.h" +#include "imstkVTKSurfaceMeshRenderDelegate.h" +#include "imstkVTKTetrahedralMeshRenderDelegate.h" -#include <vtkOpenGLVertexBufferObject.h> -#include <vtkTriangleMeshPointNormals.h> -#include <vtkOpenGLPolyDataMapper.h> +#include <vtkActor.h> +#include <vtkAlgorithmOutput.h> +#include <vtkColorTransferFunction.h> +#include <vtkGPUVolumeRayCastMapper.h> +#include <vtkImageData.h> +#include <vtkImageReader2.h> #include <vtkImageReader2Factory.h> +#include <vtkOpenGLPolyDataMapper.h> +#include <vtkOpenGLVertexBufferObject.h> #include <vtkPolyDataNormals.h> -#include <vtkImageReader2.h> -#include <vtkTransform.h> -#include <vtkImageData.h> +#include <vtkProperty.h> #include <vtkTexture.h> +#include <vtkTransform.h> #include <vtkVolume.h> -#include <vtkVector.h> -#include <vtkProp3D.h> -#include <vtkActor.h> -#include <vtkColorTransferFunction.h> -#include <vtkNew.h> +#include <vtkVolumeProperty.h> namespace imstk { +VTKRenderDelegate::VTKRenderDelegate() : + m_transform(vtkSmartPointer<vtkTransform>::New()), + m_volumeMapper(vtkSmartPointer<vtkGPUVolumeRayCastMapper>::New()), + m_volume(vtkSmartPointer<vtkVolume>::New()), + m_modelIsVolume(false), + m_actor(vtkSmartPointer<vtkActor>::New()), + m_mapper(vtkSmartPointer<vtkOpenGLPolyDataMapper>::New()) +{ + m_actor->SetMapper(m_mapper); // remove this as a default since it could be volume mapper? + m_actor->SetUserTransform(m_transform); + m_volume->SetMapper(m_volumeMapper); // remove this as a default? + /*m_volumeMapper->SetAutoAdjustSampleDistances(false); + m_volumeMapper->SetSampleDistance(0.01);*/ +} + std::shared_ptr<VTKRenderDelegate> VTKRenderDelegate::makeDelegate(std::shared_ptr<VisualModel> visualModel) { @@ -136,7 +144,14 @@ VTKRenderDelegate::makeDelegate(std::shared_ptr<VisualModel> visualModel) } case Geometry::Type::ImageData: { - return std::make_shared<VTKImageDataRenderDelegate>(visualModel); + if (visualModel->getRenderMaterial()->getDisplayMode() == RenderMaterial::DisplayMode::Points) + { + return std::make_shared<VTKPointSetRenderDelegate>(visualModel); + } + else + { + return std::make_shared<VTKImageDataRenderDelegate>(visualModel); + } } default: { @@ -176,7 +191,7 @@ void VTKRenderDelegate::setUpMapper(vtkAlgorithmOutput* source, const std::shared_ptr<VisualModel> vizModel) { - if (auto imData = vtkImageData::SafeDownCast(source->GetProducer()->GetOutputDataObject(0))) + if (vtkImageData::SafeDownCast(source->GetProducer()->GetOutputDataObject(0))) { m_volumeMapper->SetInputConnection(source); m_modelIsVolume = true; @@ -520,8 +535,8 @@ VTKRenderDelegate::updateActorPropertiesMesh() } } - /* actorProperty->SetBackfaceCulling(material->getBackfaceCulling()); - actorProperty->SetOpacity(material->getOpacity());*/ + //actorProperty->SetBackfaceCulling(material->getBackfaceCulling()); + actorProperty->SetOpacity(material->getOpacity()); // Material state is now up-to-date material->m_stateModified = false; @@ -541,7 +556,7 @@ VTKRenderDelegate::updateActorPropertiesVolumeRendering() return; } - if (VolumeRenderMaterial* volumeMat = dynamic_cast<VolumeRenderMaterial*>(material.get())) + if (auto volumeMat = std::dynamic_pointer_cast<VolumeRenderMaterial>(material)) { switch (volumeMat->getBlendMode()) { diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKRenderDelegate.h index 8205c7794b21f753aac195ad1caac9b3ae5c1f63..5569064b5958b131a02a16a61f4202f4f0762b90 100644 --- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKRenderDelegate.h +++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKRenderDelegate.h @@ -21,32 +21,34 @@ #pragma once -#include "imstkGeometry.h" -#include "imstkRenderMaterial.h" -#include "imstkVTKTextureDelegate.h" -#include "imstkTextureManager.h" -#include "imstkDebugRenderGeometry.h" -#include "imstkVisualModel.h" +#include "imstkEventObject.h" #include <vtkSmartPointer.h> -#include <vtkAlgorithmOutput.h> -#include <vtkActor.h> -#include <vtkOpenGLPolyDataMapper.h> -#include <vtkTransform.h> -#include <vtkProperty.h> -#include <vtkGPUVolumeRayCastMapper.h> -#include <vtkVolume.h> +#include <memory> + +class vtkActor; +class vtkAlgorithmOutput; +class vtkGPUVolumeRayCastMapper; +class vtkOpenGLPolyDataMapper; +class vtkProp3D; +class vtkTransform; +class vtkTexture; +class vtkVolume; namespace imstk { +class Texture; +class VisualModel; + /// /// \class VTKRenderDelegate /// /// \brief Base class for VTK render delegates /// -class VTKRenderDelegate +class VTKRenderDelegate : public EventObject { public: + virtual ~VTKRenderDelegate() override = default; /// /// \brief Instantiate proper render delegate @@ -106,20 +108,7 @@ protected: /// /// \brief Default constructor (protected) /// - VTKRenderDelegate() : - m_actor(vtkSmartPointer<vtkActor>::New()), - m_mapper(vtkSmartPointer<vtkOpenGLPolyDataMapper>::New()), - m_transform(vtkSmartPointer<vtkTransform>::New()), - m_volumeMapper(vtkSmartPointer<vtkGPUVolumeRayCastMapper>::New()), - m_volume(vtkSmartPointer<vtkVolume>::New()), - m_modelIsVolume(false) // remove? - { - m_actor->SetMapper(m_mapper); // remove this as a default since it could be volume mapper? - m_actor->SetUserTransform(m_transform); - m_volume->SetMapper(m_volumeMapper); // remove this as a default? - } - - virtual ~VTKRenderDelegate() = default; + VTKRenderDelegate(); vtkSmartPointer<vtkTransform> m_transform; diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSphereRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSphereRenderDelegate.cpp index 5945315c8c4e278c58db541b3ebf3ea383a9589b..163f4bf136d8ab3b9a9a8a43d1081387372056c5 100644 --- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSphereRenderDelegate.cpp +++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSphereRenderDelegate.cpp @@ -21,9 +21,11 @@ #include "imstkVTKSphereRenderDelegate.h" #include "imstkSphere.h" +#include "imstkVisualModel.h" -#include <vtkTransformPolyDataFilter.h> #include <vtkSphereSource.h> +#include <vtkTransform.h> +#include <vtkTransformPolyDataFilter.h> namespace imstk { diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSphereRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSphereRenderDelegate.h index 59b8af5b5f5b574815eb7bfef6584022de264f37..9443a268ad3a2d6cb953adeeb0d355c98f8178fa 100644 --- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSphereRenderDelegate.h +++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSphereRenderDelegate.h @@ -44,7 +44,7 @@ public: /// /// \brief Destructor /// - ~VTKSphereRenderDelegate() = default; + virtual ~VTKSphereRenderDelegate() override = default; /// /// \brief Update sphere source based on the sphere geometry diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.cpp index fe701e9537a5ab206d7ba6581951873603f5d70a..09ab58aec4f3ecf4a01588c0c53cb32035572688 100644 --- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.cpp +++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.cpp @@ -20,26 +20,22 @@ =========================================================================*/ #include "imstkVTKSurfaceMeshRenderDelegate.h" -#include "imstkVTKTextureDelegate.h" -#include "imstkTextureManager.h" +#include "imstkLogger.h" +#include "imstkRenderMaterial.h" #include "imstkSurfaceMesh.h" +#include "imstkTextureManager.h" +#include "imstkVisualModel.h" -#include <vtkPolyData.h> -#include <vtkPolyDataNormals.h> -#include <vtkPolyDataMapper.h> -#include <vtkPoints.h> -#include <vtkTrivialProducer.h> +#include <vtkActor.h> #include <vtkDoubleArray.h> -#include <vtkCellArray.h> #include <vtkFloatArray.h> +#include <vtkOpenGLPolyDataMapper.h> #include <vtkPointData.h> -#include <vtkImageReader2Factory.h> -#include <vtkImageReader2.h> -#include <vtkTexture.h> +#include <vtkPolyData.h> #include <vtkProperty.h> -#include <vtkOpenGLPolyDataMapper.h> +#include <vtkTexture.h> +#include <vtkTrivialProducer.h> #include <vtkVersion.h> -#include <vtkPolyDataTangents.h> namespace imstk { diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.h index ec36afd94ac2ac6e2fcf48110038f74700ddaa49..7a2bff20c168e1756161f818698b1f77b241587e 100644 --- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.h +++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.h @@ -21,7 +21,9 @@ #pragma once +#include "imstkTextureManager.h" #include "imstkVTKRenderDelegate.h" +#include "imstkVTKTextureDelegate.h" class vtkDoubleArray; @@ -45,7 +47,7 @@ public: /// /// \brief Destructor /// - ~VTKSurfaceMeshRenderDelegate() = default; + virtual ~VTKSurfaceMeshRenderDelegate() override = default; /// /// \brief Update polydata source based on the surface mesh geometry diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKTetrahedralMeshRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKTetrahedralMeshRenderDelegate.cpp index 82ea6aeeef273082a789cf7b3ff3fcb301378099..56fdaee77703064aa2bff8bbc46936b75c3314ac 100644 --- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKTetrahedralMeshRenderDelegate.cpp +++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKTetrahedralMeshRenderDelegate.cpp @@ -21,19 +21,12 @@ #include "imstkVTKTetrahedralMeshRenderDelegate.h" #include "imstkTetrahedralMesh.h" +#include "imstkVisualModel.h" -#include <vtkUnstructuredGrid.h> +#include <vtkActor.h> #include <vtkDataSetMapper.h> #include <vtkDoubleArray.h> -#include <vtkFloatArray.h> -#include <vtkCellArray.h> -#include <vtkPointData.h> -#include <vtkProperty.h> -#include <vtkPolyData.h> -#include <vtkPoints.h> -#include <vtkNew.h> - -#include <array> +#include <vtkUnstructuredGrid.h> namespace imstk { diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKTetrahedralMeshRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKTetrahedralMeshRenderDelegate.h index a19fda48873e1db5a4c817b5b85b1a8cc5f9cb46..6ac0059584ec03dd23cca094d3349a886e066648 100644 --- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKTetrahedralMeshRenderDelegate.h +++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKTetrahedralMeshRenderDelegate.h @@ -46,7 +46,7 @@ public: /// /// \brief Destructor /// - ~VTKTetrahedralMeshRenderDelegate() = default; + virtual ~VTKTetrahedralMeshRenderDelegate() override = default; /// /// \brief Update unstructured grid source based on the tetrahedral mesh diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugLinesRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugLinesRenderDelegate.cpp index 56c2f3206eb07982b147f8ba464fc91cede4f589..d0482ab637a1a5a2050ae68f07e3a31f86289883 100644 --- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugLinesRenderDelegate.cpp +++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugLinesRenderDelegate.cpp @@ -20,19 +20,13 @@ =========================================================================*/ #include "imstkVTKdebugLinesRenderDelegate.h" -#include "imstkSurfaceMesh.h" +#include "imstkDebugRenderGeometry.h" +#include "imstkVisualModel.h" -#include <vtkOpenGLPolyDataMapper.h> -#include <vtkTrivialProducer.h> -#include <vtkPolyDataMapper.h> +#include <thread> #include <vtkDoubleArray.h> -#include <vtkFloatArray.h> -#include <vtkCellArray.h> -#include <vtkPointData.h> #include <vtkPolyData.h> -#include <vtkProperty.h> -#include <vtkPoints.h> -#include <vtkLine.h> +#include <vtkTrivialProducer.h> namespace imstk { diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugLinesRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugLinesRenderDelegate.h index a1657018fda131871b19d9c62158297055326a02..c05c642b25cc18d7047e163e278c4c7edf96db87 100644 --- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugLinesRenderDelegate.h +++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugLinesRenderDelegate.h @@ -44,6 +44,8 @@ public: /// explicit VTKdbgLinesRenderDelegate(std::shared_ptr<VisualModel> visualModel); + virtual ~VTKdbgLinesRenderDelegate() override = default; + /// /// \brief Update polydata source based on the surface mesh geometry /// diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugPointsRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugPointsRenderDelegate.cpp index a4965abf37b66b86ac08fa35260eb21c10d9783f..44a606300a4b6c178d6df52c33557f9d44530001 100644 --- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugPointsRenderDelegate.cpp +++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugPointsRenderDelegate.cpp @@ -20,22 +20,12 @@ =========================================================================*/ #include "imstkVTKdebugPointsRenderDelegate.h" -#include "imstkSurfaceMesh.h" +#include "imstkDebugRenderGeometry.h" +#include "imstkVisualModel.h" -#include <vtkOpenGLPolyDataMapper.h> #include <vtkVertexGlyphFilter.h> -#include <vtkTrivialProducer.h> -#include <vtkPolyDataMapper.h> -#include <vtkSphereSource.h> #include <vtkDoubleArray.h> -#include <vtkFloatArray.h> -#include <vtkCellArray.h> -#include <vtkPointData.h> -#include <vtkPolyData.h> -#include <vtkPolyLine.h> -#include <vtkProperty.h> -#include <vtkGlyph3D.h> -#include <vtkPoints.h> +#include <thread> namespace imstk { diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugPointsRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugPointsRenderDelegate.h index 66d2ab131de269efd89f964761470803409dcbd2..b351ad7f286f7cee8acd2d6332eb2a0f658d03aa 100644 --- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugPointsRenderDelegate.h +++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugPointsRenderDelegate.h @@ -44,6 +44,8 @@ public: /// explicit VTKdbgPointsRenderDelegate(std::shared_ptr<VisualModel> visualModel); + virtual ~VTKdbgPointsRenderDelegate() override = default; + /// /// \brief Update polydata source based on the surface mesh geometry /// diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugTrianglesRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugTrianglesRenderDelegate.cpp index 144aba82292715187138a139c2b4964130e20d85..ce1bbaec2d3e22bab0f8cc4cac9bb77fa11f2543 100644 --- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugTrianglesRenderDelegate.cpp +++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugTrianglesRenderDelegate.cpp @@ -20,15 +20,13 @@ =========================================================================*/ #include "imstkVTKdebugTrianglesRenderDelegate.h" +#include "imstkDebugRenderGeometry.h" +#include "imstkVisualModel.h" -#include <vtkTrivialProducer.h> -#include <vtkPolyDataMapper.h> +#include <thread> #include <vtkDoubleArray.h> -#include <vtkFloatArray.h> -#include <vtkCellArray.h> -#include <vtkPointData.h> #include <vtkPolyData.h> -#include <vtkProperty.h> +#include <vtkTrivialProducer.h> namespace imstk { diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugTrianglesRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugTrianglesRenderDelegate.h index 69539c58a6213227fcd92fffdc183c20470ca6f7..45f0adbf5f6ef52334d8638c2a459d0ee35287c8 100644 --- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugTrianglesRenderDelegate.h +++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugTrianglesRenderDelegate.h @@ -23,8 +23,10 @@ #include "imstkVTKRenderDelegate.h" -class vtkDoubleArray; class vtkCellArray; +class vtkDoubleArray; +class vtkPoints; +class vtkPolyData; namespace imstk { @@ -44,6 +46,8 @@ public: /// explicit VTKdbgTrianglesRenderDelegate(std::shared_ptr<VisualModel> visualModel); + virtual ~VTKdbgTrianglesRenderDelegate() override = default; + /// /// \brief Update polydata source based on the surface mesh geometry /// diff --git a/Source/Rendering/VTKRenderer/imstkVTKRenderer.cpp b/Source/Rendering/VTKRenderer/imstkVTKRenderer.cpp index fef99d9167f28b46497dd8377b25d0b4a2b1f684..f78311672e68459943f7892adc0e9f3b68cd526b 100644 --- a/Source/Rendering/VTKRenderer/imstkVTKRenderer.cpp +++ b/Source/Rendering/VTKRenderer/imstkVTKRenderer.cpp @@ -20,51 +20,53 @@ =========================================================================*/ #include "imstkVTKRenderer.h" - +#include "imstkCamera.h" +#include "imstkDebugRenderGeometry.h" +#include "imstkLight.h" +#include "imstkLogger.h" #include "imstkScene.h" #include "imstkSceneObject.h" -#include "imstkCamera.h" -#include "imstkVTKRenderDelegate.h" +#include "imstkVisualModel.h" #include "imstkVTKSurfaceMeshRenderDelegate.h" -#include "imstkLight.h" -#include <vtkLightActor.h> -#include <vtkCameraActor.h> -#include <vtkAxesActor.h> -#include <vtkCullerCollection.h> #include <vtkAxesActor.h> #include <vtkCamera.h> -#include <vtkProp.h> +#include <vtkCameraActor.h> +#include <vtkCullerCollection.h> #include <vtkLight.h> +#include <vtkLightActor.h> #include <vtkRenderer.h> -#include <vtkRenderWindow.h> #include <vtkAxis.h> #include <vtkChartXY.h> #include <vtkContextActor.h> #include <vtkContextScene.h> #include <vtkDoubleArray.h> -#include <vtkIntArray.h> #include <vtkPlotBar.h> #include <vtkStringArray.h> #include <vtkTable.h> #include <vtkTextProperty.h> +#include <vtkOpenVRRenderer.h> +#include <vtkOpenVRCamera.h> +#include <vtkOpenVRRenderWindow.h> +#include <vtkOpenVRRenderWindowInteractor.h> +#include <vtkInteractorStyle3D.h> + namespace imstk { -VTKRenderer::VTKRenderer(std::shared_ptr<Scene> scene, const bool enableVR) : m_scene(scene) +VTKRenderer::VTKRenderer(std::shared_ptr<Scene> scene, const bool enableVR) : + m_scene(scene) { // create m_vtkRenderer depending on enableVR if (!enableVR) { m_vtkRenderer = vtkSmartPointer<vtkRenderer>::New(); } -#ifdef iMSTK_ENABLE_VR else { m_vtkRenderer = vtkSmartPointer<vtkOpenVRRenderer>::New(); } -#endif this->updateRenderDelegates(); @@ -149,40 +151,24 @@ VTKRenderer::VTKRenderer(std::shared_ptr<Scene> scene, const bool enableVR) : m_ // Global Axis m_AxesActor = vtkSmartPointer<vtkAxesActor>::New(); m_AxesActor->SetShaftType(vtkAxesActor::CYLINDER_SHAFT); - m_AxesActor->SetAxisLabels(false); + m_AxesActor->SetAxisLabels(true); m_debugVtkActors.push_back(m_AxesActor); // Camera and camera actor if (!enableVR) { - m_sceneVtkCamera = vtkSmartPointer<vtkCamera>::New(); + m_Camera = vtkSmartPointer<vtkCamera>::New(); } -#ifdef iMSTK_ENABLE_VR else { - m_sceneVtkCamera = vtkSmartPointer<vtkOpenVRCamera>::New(); + m_Camera = vtkSmartPointer<vtkOpenVRCamera>::New(); } -#endif - this->updateSceneCamera(scene->getCamera()); + + updateCamera(); vtkNew<vtkCameraActor> camActor; - camActor->SetCamera(m_sceneVtkCamera); + camActor->SetCamera(m_Camera); m_debugVtkActors.push_back(camActor); - // Debug camera - if (!enableVR) - { - m_defaultVtkCamera = m_vtkRenderer->GetActiveCamera(); - m_vtkRenderer->ResetCamera(); - } -#ifdef iMSTK_ENABLE_VR - else - { - // in VR mode, we keep m_defaultVtkCamera as the HMD camera - // => Do not change the active Camera - m_defaultVtkCamera = vtkSmartPointer<vtkOpenVRCamera>::New(); - m_vtkRenderer->SetActiveCamera(m_defaultVtkCamera); - } -#endif ///TODO : based on scene properties // Customize background colors @@ -198,26 +184,6 @@ VTKRenderer::VTKRenderer(std::shared_ptr<Scene> scene, const bool enableVR) : m_ m_vtkRenderer->RemoveCuller(culler); } - // set camera pos -#ifdef iMSTK_ENABLE_VR - if (enableVR) - { - m_cams.resize(2); - - // save debug camera m_camPos[0] - m_cams[0] = vtkSmartPointer<vtkOpenVRCamera>::New(); - m_cams[0]->SetPosition(m_defaultVtkCamera->GetPosition()); - m_cams[0]->SetViewUp(0.0, 1.0, 0.0); - m_cams[0]->SetDistance(10.0); // room scale factor - - // save scene camera m_camPos[1] - m_cams[1] = vtkSmartPointer<vtkOpenVRCamera>::New(); - m_cams[1]->SetPosition(m_sceneVtkCamera->GetPosition()); - m_cams[1]->SetViewUp(0.0, 1.0, 0.0); - m_cams[1]->SetDistance(1.0); // room scale factor of 1 meter - } -#endif - { // Add the benchmarking chart m_timeTableChart = vtkSmartPointer<vtkChartXY>::New(); @@ -256,32 +222,21 @@ VTKRenderer::VTKRenderer(std::shared_ptr<Scene> scene, const bool enableVR) : m_ m_timeTable->AddColumn(labels); m_timeTablePlot->SetInputData(m_timeTable, 0, 1); + m_timeTableChart->GetAxis(vtkAxis::BOTTOM)->GetLabelProperties()->SetColor(1.0, 1.0, 1.0); vtkAxis* axisY = m_timeTableChart->GetAxis(vtkAxis::LEFT); - //axisY->SetRange(xIndices->GetRange()); + axisY->GetLabelProperties()->SetColor(1.0, 1.0, 1.0); + axisY->SetGridVisible(false); axisY->SetCustomTickPositions(xIndices, labels); } } -vtkSmartPointer<vtkRenderer> -VTKRenderer::getVtkRenderer() const -{ - return m_vtkRenderer; -} - void VTKRenderer::setMode(const Renderer::Mode mode, const bool enableVR) { -#ifdef iMSTK_ENABLE_VR - vtkOpenVRRenderWindow* renWin = nullptr; if (enableVR) { - renWin = vtkOpenVRRenderWindow::SafeDownCast(m_vtkRenderer->GetRenderWindow()); - if (!renWin || !m_vtkRenderer) - { - return; - } + return; } -#endif if (mode == Mode::Empty && m_currentMode != Mode::Empty) { this->removeActors(m_objectVtkActors); @@ -291,11 +246,6 @@ VTKRenderer::setMode(const Renderer::Mode mode, const bool enableVR) { this->removeActors(m_debugVtkActors); } - // do not change active camera in VR - if (!enableVR) - { - m_vtkRenderer->SetActiveCamera(m_defaultVtkCamera); - } } else if (mode == Mode::Debug && m_currentMode != Mode::Debug) { @@ -309,19 +259,6 @@ VTKRenderer::setMode(const Renderer::Mode mode, const bool enableVR) m_vtkRenderer->AddLight(light); } } - // do not change active camera in VR - if (!enableVR) - { - m_vtkRenderer->SetActiveCamera(m_defaultVtkCamera); - m_vtkRenderer->ResetCamera(); - } -#ifdef iMSTK_ENABLE_VR - else // go to debug position camera - { // apply debug camera - static_cast<vtkOpenVRCamera*>(m_vtkRenderer->GetActiveCamera())->DeepCopy(m_cams[0]); - m_vtkRenderer->ResetCameraClippingRange(); - } -#endif } else if (mode == Mode::Simulation && m_currentMode != Mode::Simulation) { @@ -336,29 +273,12 @@ VTKRenderer::setMode(const Renderer::Mode mode, const bool enableVR) else if (m_currentMode == Mode::Debug) { this->removeActors(m_debugVtkActors); - -#ifdef iMSTK_ENABLE_VR - // save last debug position camera - if (enableVR) - { - static_cast<vtkOpenVRCamera*>(m_vtkRenderer->GetActiveCamera())->DeepCopy(m_cams[0]); - } -#endif - } - // do not change active camera in VR - if (!enableVR) - { - m_vtkRenderer->SetActiveCamera(m_sceneVtkCamera); } -#ifdef iMSTK_ENABLE_VR - else // go to Predefined sceneVtkCamera position - { // apply scene camera - static_cast<vtkOpenVRCamera*>(m_vtkRenderer->GetActiveCamera())->DeepCopy(m_cams[1]); - } -#endif - m_vtkRenderer->ResetCameraClippingRange(); } + // Reset the camera + m_Camera = vtkSmartPointer<vtkCamera>::New(); + Renderer::setMode(mode, enableVR); } @@ -465,18 +385,24 @@ VTKRenderer::getTimeTableVisibility() const } void -VTKRenderer::updateSceneCamera(std::shared_ptr<Camera> imstkCam) +VTKRenderer::updateCamera() { - // Get imstk Camera info - const auto p = imstkCam->getPosition(); - const auto f = imstkCam->getFocalPoint(); - const auto v = imstkCam->getViewUp(); - - // Update vtk Camera - m_sceneVtkCamera->SetPosition(p[0], p[1], p[2]); - m_sceneVtkCamera->SetFocalPoint(f[0], f[1], f[2]); - m_sceneVtkCamera->SetViewUp(v[0], v[1], v[2]); - m_sceneVtkCamera->SetViewAngle(imstkCam->getFieldOfView()); + std::shared_ptr<Camera> cam = m_scene->getActiveCamera(); + getVtkRenderer()->SetActiveCamera(m_Camera); + + // Update the camera to obtain corrected view/proj matrices + cam->update(); + + // Get the view matrix + const Mat4d& invView = cam->getInvView(); + + const double eyePos[3] = { invView(0, 3), invView(1, 3), invView(2, 3) }; + const double forward[3] = { invView(0, 2), invView(1, 2), invView(2, 2) }; + const double up[3] = { invView(0, 1), invView(1, 1), invView(2, 1) }; + m_Camera->SetPosition(eyePos); + m_Camera->SetFocalPoint(eyePos[0] - forward[0], eyePos[1] - forward[1], eyePos[2] - forward[2]); + m_Camera->SetViewUp(up[0], up[1], up[2]); + m_Camera->SetViewAngle(cam->getFieldOfView()); } void diff --git a/Source/Rendering/VTKRenderer/imstkVTKRenderer.h b/Source/Rendering/VTKRenderer/imstkVTKRenderer.h index 8e619b29e5efb23c18639ed1ba9c8e4dee3a2d59..6d2e7c112c534027b5c6bcb5db162ff12797a629 100644 --- a/Source/Rendering/VTKRenderer/imstkVTKRenderer.h +++ b/Source/Rendering/VTKRenderer/imstkVTKRenderer.h @@ -22,18 +22,10 @@ #pragma once #include "imstkRenderer.h" -#include "imstkVTKTextureDelegate.h" #include "imstkTextureManager.h" +#include "imstkVTKTextureDelegate.h" #include <vtkSmartPointer.h> -#ifdef iMSTK_ENABLE_VR -#include <vtkOpenVRRenderer.h> -#include <vtkOpenVRCamera.h> -#include <vtkOpenVRRenderWindow.h> -#include <vtkOpenVRRenderWindowInteractor.h> -#include <vtkInteractorStyle3D.h> -#endif - #include <unordered_map> class vtkAxesActor; @@ -41,6 +33,7 @@ class vtkCamera; class vtkChartXY; class vtkContextActor; class vtkLight; +class vtkOpenVRCamera; class vtkPlotBar; class vtkProp; class vtkRenderer; @@ -51,29 +44,21 @@ namespace imstk class Scene; class Camera; class VTKRenderDelegate; -//class TextureManager; /// /// \class VTKRenderer /// -/// \brief +/// \brief Wraps a vtkRenderer /// class VTKRenderer : public Renderer { public: - /// - /// \brief Constructor - /// VTKRenderer(std::shared_ptr<Scene> scene, const bool enableVR); + virtual ~VTKRenderer() override = default; +public: /// - /// \brief Default destructor - /// - ~VTKRenderer() = default; - - /// - /// \brief Set/Get the rendering mode which defined the - /// visibility of the renderer actors and the default camera + /// \brief Set the rendering mode to display debug actors or not /// void setMode(const Mode mode, const bool enableVR) override; @@ -114,9 +99,9 @@ public: bool getTimeTableVisibility() const; /// - /// \brief Updates the scene camera's position and orientation + /// \brief Updates the camera /// - void updateSceneCamera(std::shared_ptr<Camera> imstkCam); + void updateCamera(); /// /// \brief Updates the render delegates @@ -131,7 +116,7 @@ public: /// /// \brief Returns VTK renderer /// - vtkSmartPointer<vtkRenderer> getVtkRenderer() const; + vtkSmartPointer<vtkRenderer> getVtkRenderer() const { return m_vtkRenderer; } /// /// \brief Update background colors @@ -152,9 +137,8 @@ protected: protected: vtkSmartPointer<vtkRenderer> m_vtkRenderer; - // cameras - vtkSmartPointer<vtkCamera> m_defaultVtkCamera; - vtkSmartPointer<vtkCamera> m_sceneVtkCamera; + // Camera + vtkSmartPointer<vtkCamera> m_Camera; // lights std::vector<vtkSmartPointer<vtkLight>> m_vtkLights; @@ -172,9 +156,6 @@ protected: std::shared_ptr<Scene> m_scene; TextureManager<VTKTextureDelegate> m_textureManager; -#ifdef iMSTK_ENABLE_VR - std::vector<vtkSmartPointer<vtkOpenVRCamera>> m_cams; -#endif vtkSmartPointer<vtkChartXY> m_timeTableChart; vtkSmartPointer<vtkContextActor> m_timeTableChartActor; diff --git a/Source/Rendering/VTKRenderer/imstkVTKTextureDelegate.cpp b/Source/Rendering/VTKRenderer/imstkVTKTextureDelegate.cpp index 513a666ae652c964de2e40317765466d725aa67b..ba8451518defd0a29e6a22143d33531b33fe5365 100644 --- a/Source/Rendering/VTKRenderer/imstkVTKTextureDelegate.cpp +++ b/Source/Rendering/VTKRenderer/imstkVTKTextureDelegate.cpp @@ -20,13 +20,13 @@ =========================================================================*/ #include "imstkVTKTextureDelegate.h" +#include "imstkLogger.h" +#include "imstkTexture.h" +#include <vtkImageFlip.h> #include <vtkImageReader2Factory.h> #include <vtkPNGReader.h> -#include <vtkImageReader2.h> -#include <vtkImageFlip.h> #include <vtkTexture.h> -#include <vtkImageCast.h> namespace imstk { diff --git a/Source/Rendering/imstkRenderer.h b/Source/Rendering/imstkRenderer.h index d675dc15120bd76035bb4344901e91c06c1f39d7..c53d28f13bfe7f0666374df95761465d16b3e66e 100644 --- a/Source/Rendering/imstkRenderer.h +++ b/Source/Rendering/imstkRenderer.h @@ -52,17 +52,23 @@ public: Simulation }; - Renderer() : m_config(std::make_shared<rendererConfig>()) {} + Renderer() : m_config(std::make_shared<rendererConfig>()) { } + virtual ~Renderer() = default; +public: /// /// \brief Set rendering mode /// - virtual void setMode(const Renderer::Mode mode, const bool enableVR); + virtual void setMode(const Renderer::Mode mode, const bool enableVR) + { + m_VrEnabled = enableVR; + m_currentMode = mode; + } /// /// \brief Get rendering mode /// - virtual const Renderer::Mode& getMode(); + virtual const Renderer::Mode& getMode() const { return m_currentMode; } /// /// \brief Update background colors @@ -71,7 +77,7 @@ public: protected: bool m_VrEnabled = false; - Renderer::Mode m_currentMode = Renderer::Mode::Empty; + Renderer::Mode m_currentMode = Renderer::Mode::Simulation; std::shared_ptr<rendererConfig> m_config; }; diff --git a/Source/Scene/imstkCollisionGraph.cpp b/Source/Scene/imstkCollisionGraph.cpp index 6805e2faa8b2f64aa9d9dab2681bdf7f4978a515..dee076f0a5ef6b52698f041da96b6cb31bfef0b5 100644 --- a/Source/Scene/imstkCollisionGraph.cpp +++ b/Source/Scene/imstkCollisionGraph.cpp @@ -20,9 +20,7 @@ =========================================================================*/ #include "imstkCollisionGraph.h" -#include "imstkLogger.h" #include "imstkObjectInteractionPair.h" -#include "imstkSceneObject.h" namespace imstk { diff --git a/Source/Scene/imstkCollisionGraph.h b/Source/Scene/imstkCollisionGraph.h index a547067b0cacd57181f4b5559789ed1560bc3354..474b87fbade93b2a9a53cc9888c09ac15a2d0e8f 100644 --- a/Source/Scene/imstkCollisionGraph.h +++ b/Source/Scene/imstkCollisionGraph.h @@ -49,7 +49,7 @@ public: /// /// \brief Default destructor /// - ~CollisionGraph() = default; + virtual ~CollisionGraph() = default; public: /// diff --git a/Source/Scene/imstkCollisionPair.cpp b/Source/Scene/imstkCollisionPair.cpp index ae296795d07cf8366e02c4d56b8fea12adc381e9..704bf103ade4348aea11d91d21f0011ce2ef513e 100644 --- a/Source/Scene/imstkCollisionPair.cpp +++ b/Source/Scene/imstkCollisionPair.cpp @@ -21,10 +21,8 @@ limitations under the License. #include "imstkCollisionPair.h" #include "imstkCollidingObject.h" -#include "imstkCollisionData.h" -#include "imstkDynamicObject.h" -#include "imstkInteractionPair.h" -#include "imstkLogger.h" +#include "imstkCollisionDetection.h" +#include "imstkCollisionHandling.h" #include "imstkTaskGraph.h" namespace imstk diff --git a/Source/Scene/imstkCollisionPair.h b/Source/Scene/imstkCollisionPair.h index 41147bbc5bb57e1887c394c372c61ca14b73a927..73732c90ffc703c24384c45babfa93893ff71ddc 100644 --- a/Source/Scene/imstkCollisionPair.h +++ b/Source/Scene/imstkCollisionPair.h @@ -21,21 +21,22 @@ limitations under the License. #pragma once -#include "imstkCollisionDetection.h" -#include "imstkCollisionHandling.h" #include "imstkObjectInteractionPair.h" namespace imstk { struct CollisionData; class CollidingObject; +class CollisionDetection; +class CollisionHandling; /// /// \class CollisionPair /// /// \brief CollisionPair is a specialization of InteractionPair that adds Handler functions. /// The handler functions precede the interaction node/step as their own computational node/step. -/// The handler functions may be a singular handler node or two separate concurrent nodes. +/// The handler functions may be a singular handler node (that handles both AB concurrently) or +/// two separate concurrent nodes. /// class CollisionPair : public ObjectInteractionPair { @@ -57,7 +58,7 @@ public: std::shared_ptr<CollisionDetection> cd, std::shared_ptr<CollisionHandling> chAB); - ~CollisionPair() = default; + virtual ~CollisionPair() override = default; public: /// \brief TODO diff --git a/Source/Scene/imstkInteractionPair.h b/Source/Scene/imstkInteractionPair.h index f2b5337f1c306174a5f03b30d65648b7d74afad5..585bba397924de58261c2c42101784a6416ee2bf 100644 --- a/Source/Scene/imstkInteractionPair.h +++ b/Source/Scene/imstkInteractionPair.h @@ -31,7 +31,9 @@ class TaskNode; /// /// \class InteractionPair /// -/// \brief This class defines an interaction between nodes +/// \brief This class defines an interaction between 2 sets of nodes +/// Given a set of input and output nodes, the interactionFunction will be +/// inserted /// class InteractionPair { @@ -47,6 +49,12 @@ public: const Inputs& getTaskNodeInputs() const { return m_taskNodeInputs; } const Outputs& getTaskNodeOutputs() const { return m_taskNodeOutputs; } +public: + /// + /// \brief Modifies the computational graph + /// + void compute(); + protected: Inputs m_taskNodeInputs; ///> The interacting nodes Outputs m_taskNodeOutputs; ///> The interacting nodes diff --git a/Source/Scene/imstkObjectInteractionFactory.cpp b/Source/Scene/imstkObjectInteractionFactory.cpp index 0541f7448cf2c45a0df711427f2ffe55c8a857d3..34b4fc302311904e70c426cd03f89fc47fb91d72 100644 --- a/Source/Scene/imstkObjectInteractionFactory.cpp +++ b/Source/Scene/imstkObjectInteractionFactory.cpp @@ -22,15 +22,13 @@ limitations under the License. #include "imstkObjectInteractionFactory.h" #include "imstkBoneDrillingCH.h" #include "imstkCDObjectFactory.h" -#include "imstkCollidingObject.h" #include "imstkCollisionData.h" -#include "imstkCollisionDetection.h" #include "imstkFeDeformableObject.h" -#include "imstkLogger.h" #include "imstkPbdObject.h" #include "imstkPbdObjectCollisionPair.h" #include "imstkPenaltyCH.h" #include "imstkPickingCH.h" +#include "imstkImplicitGeometryToPointSetCD.h" #include "imstkSPHCollisionHandling.h" #include "imstkSPHObject.h" @@ -61,7 +59,7 @@ makeObjectInteractionPair(std::shared_ptr<CollidingObject> obj1, std::shared_ptr //} else if (intType == InteractionType::SphObjToCollidingObjCollision && isType<SPHObject>(obj1)) { - // Setup CD, and collision data + // Setup CD and collision data std::shared_ptr<CollisionData> colData = std::make_shared<CollisionData>(); std::shared_ptr<CollisionDetection> colDetect = makeCollisionDetectionObject(cdType, obj1->getCollidingGeometry(), obj2->getCollidingGeometry(), colData); @@ -71,9 +69,19 @@ makeObjectInteractionPair(std::shared_ptr<CollidingObject> obj1, std::shared_ptr results = std::make_shared<CollisionPair>(obj1, obj2, colDetect, colHandler, nullptr); } + else if (intType == InteractionType::SphObjToCollidingObjSDFCollision && isType<SPHObject>(obj1)) + { + // Setup CD and collision data + std::shared_ptr<CollisionData> colData = std::make_shared<CollisionData>(); + std::shared_ptr<CollisionDetection> colDetect = makeCollisionDetectionObject(cdType, obj1->getCollidingGeometry(), obj2->getCollidingGeometry(), colData); + + // Setup the handler + std::shared_ptr<SPHCollisionHandling> colHandler = std::make_shared<SPHCollisionHandling>(CollisionHandling::Side::B, colData, std::dynamic_pointer_cast<SPHObject>(obj1)); + results = std::make_shared<CollisionPair>(obj2, obj1, colDetect, colHandler, nullptr); + } else if (intType == InteractionType::FemObjToCollidingObjNodalPicking && isType<FeDeformableObject>(obj1)) { - // Setup CD, and collision data + // Setup CD and collision data std::shared_ptr<CollisionData> colData = std::make_shared<CollisionData>(); std::shared_ptr<CollisionDetection> colDetect = makeCollisionDetectionObject(cdType, obj1->getCollidingGeometry(), obj2->getCollidingGeometry(), colData); @@ -85,7 +93,7 @@ makeObjectInteractionPair(std::shared_ptr<CollidingObject> obj1, std::shared_ptr } else if (intType == InteractionType::FemObjToCollidingObjPenaltyForce && isType<FeDeformableObject>(obj1)) { - // Setup CD, and collision data + // Setup CD and collision data std::shared_ptr<CollisionData> colData = std::make_shared<CollisionData>(); std::shared_ptr<CollisionDetection> colDetect = makeCollisionDetectionObject(cdType, obj1->getCollidingGeometry(), obj2->getCollidingGeometry(), colData); @@ -93,9 +101,9 @@ makeObjectInteractionPair(std::shared_ptr<CollidingObject> obj1, std::shared_ptr std::shared_ptr<PenaltyCH> colHandler = std::make_shared<PenaltyCH>(CollisionHandling::Side::A, colData, obj1); } - else if (intType == InteractionType::FemObjToCollidingObjBoneDrilling && isType<FeDeformableObject>(obj1)) + else if (intType == InteractionType::CollidingObjToCollidingObjBoneDrilling) { - // Setup CD, and collision data + // Setup CD and collision data std::shared_ptr<CollisionData> colData = std::make_shared<CollisionData>(); std::shared_ptr<CollisionDetection> colDetect = makeCollisionDetectionObject(cdType, obj1->getCollidingGeometry(), obj2->getCollidingGeometry(), colData); diff --git a/Source/Scene/imstkObjectInteractionFactory.h b/Source/Scene/imstkObjectInteractionFactory.h index fa6fb32090c3f062e1372d315537655df493be31..aea3117e39e69d6359b6140d41e24f666af0f4e5 100644 --- a/Source/Scene/imstkObjectInteractionFactory.h +++ b/Source/Scene/imstkObjectInteractionFactory.h @@ -22,11 +22,11 @@ limitations under the License. #pragma once #include "imstkCollisionDetection.h" -#include "imstkObjectInteractionPair.h" namespace imstk { class CollidingObject; +class ObjectInteractionPair; // Predefined standard/types of interaction from imstk enum class InteractionType @@ -35,6 +35,7 @@ enum class InteractionType PbdObjToCollidingObjCollision, SphObjToCollidingObjCollision, + SphObjToCollidingObjSDFCollision, FemObjToCollidingObjCollision, //RigidObjToCollidingObjCollision, @@ -43,13 +44,14 @@ enum class InteractionType FemObjToCollidingObjPenaltyForce, FemObjToCollidingObjBoneDrilling, FemObjToCollidingObjNodalPicking, + SphObjToPhysiologyObjCoupling, + CollidingObjToCollidingObjBoneDrilling - SphObjToPhysiologyObjCoupling }; /// /// \brief Factory for InteractionPairs, returns nullptr and logs warning if failed /// -extern std::shared_ptr<ObjectInteractionPair> makeObjectInteractionPair(std::shared_ptr<CollidingObject> obj1, std::shared_ptr<CollidingObject> obj2, - InteractionType intType, CollisionDetection::Type cdType); +std::shared_ptr<ObjectInteractionPair> makeObjectInteractionPair(std::shared_ptr<CollidingObject> obj1, std::shared_ptr<CollidingObject> obj2, + InteractionType intType, CollisionDetection::Type cdType); } diff --git a/Source/Scene/imstkPbdObjectCollisionPair.h b/Source/Scene/imstkPbdObjectCollisionPair.h index fb476aeef6de4a26cfbd49af7a9b9378e649eff5..3c44d115e29ba38610aad1f69ffb00555e7b5cbc 100644 --- a/Source/Scene/imstkPbdObjectCollisionPair.h +++ b/Source/Scene/imstkPbdObjectCollisionPair.h @@ -22,6 +22,7 @@ limitations under the License. #pragma once #include "imstkCollisionPair.h" +#include "imstkCollisionDetection.h" namespace imstk { @@ -39,6 +40,8 @@ public: PbdObjectCollisionPair(std::shared_ptr<PbdObject> obj1, std::shared_ptr<PbdObject> obj2, CollisionDetection::Type cdType = CollisionDetection::Type::MeshToMeshBruteForce); + virtual ~PbdObjectCollisionPair() override = default; + void apply() override; private: diff --git a/Source/Scene/imstkRigidObjectCollidingCollisionPair.cpp b/Source/Scene/imstkRigidObjectCollidingCollisionPair.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5b61f1e31a435ab0b088671c527e755fd8cc137e --- /dev/null +++ b/Source/Scene/imstkRigidObjectCollidingCollisionPair.cpp @@ -0,0 +1,62 @@ +/*========================================================================= + +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 "imstkRigidObjectCollidingCollisionPair.h" +#include "imstkCDObjectFactory.h" +#include "imstkCollisionData.h" +#include "imstkRigidBodyCH.h" +#include "imstkRigidBodyModel2.h" +#include "imstkRigidObject2.h" +#include "imstkTaskGraph.h" + +namespace imstk +{ +namespace expiremental +{ +RigidObjectCollidingCollisionPair::RigidObjectCollidingCollisionPair( + std::shared_ptr<RigidObject2> obj1, std::shared_ptr<CollidingObject> obj2, + CollisionDetection::Type cdType, const double stiffness, const double frictionalCoefficient) : + CollisionPair(obj1, obj2) +{ + std::shared_ptr<RigidBodyModel2> rbdModel = obj1->getRigidBodyModel2(); + + if (rbdModel == nullptr) + { + LOG(WARNING) << "RigidCollidingObjectCollisionPair, could not create"; + return; + } + + // Define where collision interaction happens + m_taskNodeInputs.first.push_back(rbdModel->getComputeTentativeVelocitiesNode()); + m_taskNodeInputs.second.push_back(obj2->getTaskGraph()->getSource()); + + m_taskNodeOutputs.first.push_back(rbdModel->getSolveNode()); + m_taskNodeOutputs.second.push_back(obj2->getUpdateNode()); + + // Setup the CD + m_colData = std::make_shared<CollisionData>(); + setCollisionDetection(makeCollisionDetectionObject(cdType, obj1->getCollidingGeometry(), obj2->getCollidingGeometry(), m_colData)); + + // Setup the handlers for each side + setCollisionHandlingA(std::make_shared<RigidBodyCH>(CollisionHandling::Side::A, m_colData, obj1, nullptr, stiffness, frictionalCoefficient)); +} +} +} \ No newline at end of file diff --git a/Source/Scene/imstkRigidObjectCollidingCollisionPair.h b/Source/Scene/imstkRigidObjectCollidingCollisionPair.h new file mode 100644 index 0000000000000000000000000000000000000000..5c61116f33092e17aefc0df68fa80d1beff2ef7d --- /dev/null +++ b/Source/Scene/imstkRigidObjectCollidingCollisionPair.h @@ -0,0 +1,47 @@ +/*========================================================================= + +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 "imstkCollisionPair.h" +#include "imstkCollisionDetection.h" + +namespace imstk +{ +namespace expiremental +{ +class RigidObject2; + +/// +/// \class RigidObjectCollidingCollisionPair +/// +/// \brief This class defines a collision interaction between two RigidObjects +/// +class RigidObjectCollidingCollisionPair : public CollisionPair +{ +public: + RigidObjectCollidingCollisionPair(std::shared_ptr<RigidObject2> obj1, std::shared_ptr<CollidingObject> obj2, + CollisionDetection::Type cdType, const double stiffness = 0.0, const double frictionalCoefficient = 0.8); + + virtual ~RigidObjectCollidingCollisionPair() override = default; +}; +} +} \ No newline at end of file diff --git a/Source/Scene/imstkRigidObjectCollisionPair.cpp b/Source/Scene/imstkRigidObjectCollisionPair.cpp new file mode 100644 index 0000000000000000000000000000000000000000..949733b0a25383ed9fd26151e5e580dea48d934c --- /dev/null +++ b/Source/Scene/imstkRigidObjectCollisionPair.cpp @@ -0,0 +1,91 @@ +/*========================================================================= + +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 "imstkRigidObjectCollisionPair.h" +#include "imstkCDObjectFactory.h" +#include "imstkCollisionData.h" +#include "imstkRigidBodyCH.h" +#include "imstkRigidObject2.h" +#include "imstkTaskGraph.h" +#include "imstkRigidBodyModel2.h" +#include "imstkLogger.h" + +namespace imstk +{ +namespace expiremental +{ +RigidObjectCollisionPair::RigidObjectCollisionPair(std::shared_ptr<RigidObject2> obj1, std::shared_ptr<RigidObject2> obj2, + CollisionDetection::Type cdType) : CollisionPair(obj1, obj2) +{ + std::shared_ptr<RigidBodyModel2> model1 = obj1->getRigidBodyModel2(); + std::shared_ptr<RigidBodyModel2> model2 = obj2->getRigidBodyModel2(); + + if (model1 == nullptr || model2 == nullptr) + { + LOG(WARNING) << "RigidObjectCollisionPair, could not create"; + return; + } + + // Here we use RigidBodyCH which generates constraints for the rigid body model + // This step is done *after* tentative velocities have been computed but *before* + // constraints and new velocities are solved. + + // Define where collision interaction happens + m_taskNodeInputs.first.push_back(model1->getComputeTentativeVelocitiesNode()); + m_taskNodeInputs.second.push_back(model2->getComputeTentativeVelocitiesNode()); + + m_taskNodeOutputs.first.push_back(model1->getSolveNode()); + m_taskNodeOutputs.second.push_back(model2->getSolveNode()); + + // Setup the CD + m_colData = std::make_shared<CollisionData>(); + setCollisionDetection(makeCollisionDetectionObject(cdType, obj1->getCollidingGeometry(), obj2->getCollidingGeometry(), m_colData)); + + // Setup the handler + CollisionHandling::Side side = CollisionHandling::Side::AB; + // If both objects use the same model, we need only add one two-way constraint to the system + if (model1 == model2) + { + side = CollisionHandling::Side::AB; + } + else + { + LOG(WARNING) << "RigidObjectCollisionPair, specified RigidObjects have differing models, one-way constraints not supported yet"; + return; + } + std::shared_ptr<RigidBodyCH> ch = std::make_shared<RigidBodyCH>(side, m_colData, obj1, obj2); + setCollisionHandlingAB(ch); +} + +void +RigidObjectCollisionPair::apply() +{ + // Do the normal insertions + CollisionPair::apply(); + + // But then also insert one above the CD for updating the collision geometry + /*m_objects.first->getTaskGraph()->insertBefore(m_colDetect->getTaskNode(), + std::make_shared<TaskNode>(std::bind(&DynamicObject::updatePhysicsGeometry, m_objects.first), "UpdateGeometry")); + m_objects.second->getTaskGraph()->insertBefore(m_colDetect->getTaskNode(), + std::make_shared<TaskNode>(std::bind(&DynamicObject::updatePhysicsGeometry, m_objects.first), "UpdateGeometry"));*/ +} +} +} \ No newline at end of file diff --git a/Source/SimulationManager/VTKRenderer/imstkOpenVRCommand.h b/Source/Scene/imstkRigidObjectCollisionPair.h similarity index 50% rename from Source/SimulationManager/VTKRenderer/imstkOpenVRCommand.h rename to Source/Scene/imstkRigidObjectCollisionPair.h index 93d561e6427841905aab1dad4cfb393141df4cee..29cf8bf4c3f5017e4fb5126d31611e5860df91a3 100644 --- a/Source/SimulationManager/VTKRenderer/imstkOpenVRCommand.h +++ b/Source/Scene/imstkRigidObjectCollisionPair.h @@ -21,51 +21,32 @@ limitations under the License. #pragma once -#include <functional> -#include <vtkCommand.h> +#include "imstkCollisionPair.h" +#include "imstkCollisionDetection.h" namespace imstk { -class SimulationManager; - -/// \brief TODO -class OpenVRCommand : public vtkCommand +namespace expiremental +{ +class RigidObject2; + +/// +/// \class RigidObjectObjectCollisionPair +/// +/// \brief This class defines a collision interaction between two RigidObjects +/// This involves a RigidObjCH which will generate 2 way or 1 way constraints for the RigidBodyModel/s +/// depending on which system they belong too +/// +class RigidObjectCollisionPair : public CollisionPair { public: - static OpenVRCommand* New() - { - return new OpenVRCommand; - } - - /// - /// \brief Set the simulation manager - /// - void SetSimulationManager(SimulationManager* manager = nullptr) - { - m_simManager = manager; - } - - /// - /// \brief TODO - /// - virtual void Execute( - vtkObject* caller, - unsigned long eventId, - void* callData) override; + RigidObjectCollisionPair(std::shared_ptr<RigidObject2> obj1, std::shared_ptr<RigidObject2> obj2, + CollisionDetection::Type cdType); -protected: + virtual ~RigidObjectCollisionPair() override = default; - /// - /// \brief Constructor - /// - OpenVRCommand() - {} - - /// - /// \brief Destructor - /// - virtual ~OpenVRCommand() = default; - - SimulationManager* m_simManager = nullptr; ///> SimulationManager owning the current simulation being interacted with +public: + void apply() override; }; -} // imstk +} +} \ No newline at end of file diff --git a/Source/Scene/imstkRigidObjectLevelSetCollisionPair.cpp b/Source/Scene/imstkRigidObjectLevelSetCollisionPair.cpp new file mode 100644 index 0000000000000000000000000000000000000000..063d902210648454b0cbfed3b224b8fe81b5ccad --- /dev/null +++ b/Source/Scene/imstkRigidObjectLevelSetCollisionPair.cpp @@ -0,0 +1,72 @@ +/*========================================================================= + +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 "imstkRigidObjectLevelSetCollisionPair.h" +#include "imstkCDObjectFactory.h" +#include "imstkCollisionData.h" +#include "imstkLevelSetCH.h" +#include "imstkLevelSetDeformableObject.h" +#include "imstkLevelSetModel.h" +#include "imstkRigidBodyCH.h" +#include "imstkRigidBodyModel2.h" +#include "imstkRigidObject2.h" +#include "imstkTaskGraph.h" + +namespace imstk +{ +namespace expiremental +{ +RigidObjectLevelSetCollisionPair::RigidObjectLevelSetCollisionPair(std::shared_ptr<RigidObject2> obj1, std::shared_ptr<LevelSetDeformableObject> obj2) : + CollisionPair(obj1, obj2) +{ + std::shared_ptr<RigidBodyModel2> rbdModel = obj1->getRigidBodyModel2(); + std::shared_ptr<LevelSetModel> lvlSetModel = obj2->getLevelSetModel(); + + if (rbdModel == nullptr || lvlSetModel == nullptr) + { + LOG(WARNING) << "RigidObjectCollisionPair, could not create"; + return; + } + + // Graph of explicit interaction + // [compute tentative velocities] [lvlSetSource] + // [CD] + // [Add rigid constraints] [Apply impulses] + // [Solve rbd system] [Evolve levelset] + // Here the CH's adds constraints to the system on the LHS, and impulses to the levelset RHS + + // Define where collision interaction happens + m_taskNodeInputs.first.push_back(rbdModel->getComputeTentativeVelocitiesNode()); + m_taskNodeInputs.second.push_back(lvlSetModel->getTaskGraph()->getSource()); + + m_taskNodeOutputs.first.push_back(rbdModel->getSolveNode()); + m_taskNodeOutputs.second.push_back(lvlSetModel->getQuantityEvolveNode(0)); + + // Setup the CD + m_colData = std::make_shared<CollisionData>(); + setCollisionDetection(makeCollisionDetectionObject(CollisionDetection::Type::PointSetToImplicit, obj1->getCollidingGeometry(), obj2->getCollidingGeometry(), m_colData)); + + // Setup the handlers for each side + setCollisionHandlingA(std::make_shared<RigidBodyCH>(CollisionHandling::Side::A, m_colData, obj1, nullptr, 0.0, 0.0)); + setCollisionHandlingB(std::make_shared<LevelSetCH>(CollisionHandling::Side::B, m_colData, obj2, obj1)); +} +} +} \ No newline at end of file diff --git a/Source/Scene/imstkRigidObjectLevelSetCollisionPair.h b/Source/Scene/imstkRigidObjectLevelSetCollisionPair.h new file mode 100644 index 0000000000000000000000000000000000000000..8bd6b806ea860a53d29ce2148c895174f73be104 --- /dev/null +++ b/Source/Scene/imstkRigidObjectLevelSetCollisionPair.h @@ -0,0 +1,48 @@ +/*========================================================================= + +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 "imstkCollisionPair.h" +#include "imstkCollisionDetection.h" + +namespace imstk +{ +class LevelSetDeformableObject; + +namespace expiremental +{ +class RigidObject2; + +/// +/// \class RigidObjectObjectCollisionPair +/// +/// \brief This class defines a collision interaction between a RigidObject +/// and levelset. +/// +class RigidObjectLevelSetCollisionPair : public CollisionPair +{ +public: + RigidObjectLevelSetCollisionPair(std::shared_ptr<RigidObject2> obj1, std::shared_ptr<LevelSetDeformableObject> obj2); + virtual ~RigidObjectLevelSetCollisionPair() override = default; +}; +} +} \ No newline at end of file diff --git a/Source/Scene/imstkScene.cpp b/Source/Scene/imstkScene.cpp index b7c06707d772bc16a32a57038f702ccef30960da..31180413a3a86d54ccdddc966b01225e1c2e94d0 100644 --- a/Source/Scene/imstkScene.cpp +++ b/Source/Scene/imstkScene.cpp @@ -22,46 +22,45 @@ #include "imstkScene.h" #include "imstkCamera.h" #include "imstkCameraController.h" -#include "imstkCollidingObject.h" +#include "imstkCollisionDetection.h" #include "imstkCollisionGraph.h" #include "imstkCollisionPair.h" #include "imstkDebugRenderGeometry.h" #include "imstkFeDeformableObject.h" -#include "imstkDynamicObject.h" #include "imstkFEMDeformableBodyModel.h" -#include "imstkInteractionPair.h" #include "imstkLight.h" +#include "imstkLogger.h" #include "imstkParallelUtils.h" -#include "imstkPbdObject.h" #include "imstkRigidBodyWorld.h" -#include "imstkSceneObject.h" -#include "imstkSceneObjectControllerBase.h" #include "imstkSequentialTaskGraphController.h" #include "imstkTaskGraph.h" #include "imstkTaskGraphVizWriter.h" #include "imstkTbbTaskGraphController.h" #include "imstkTimer.h" +#include "imstkTrackingDeviceControl.h" +#include "imstkVisualModel.h" namespace imstk { Scene::Scene(const std::string& name, std::shared_ptr<SceneConfig> config) : - m_name(name), - m_camera(std::make_shared<Camera>()), + m_activeCamera(nullptr), + m_computeTimesLock(std::make_shared<ParallelUtils::SpinLock>()), m_collisionGraph(std::make_shared<CollisionGraph>()), m_config(config), - m_taskGraph(std::make_shared<TaskGraph>("Scene_" + name + "_Source", "Scene_" + name + "_Sink")), - computeTimesLock(std::make_shared<ParallelUtils::SpinLock>()) + m_name(name), + m_taskGraph(std::make_shared<TaskGraph>("Scene_" + name + "_Source", "Scene_" + name + "_Sink")) { -} + std::shared_ptr<Camera> defaultCam = std::make_shared<Camera>(); + defaultCam->setPosition(0.0, 2.0, -15.0); + defaultCam->setFocalPoint(0.0, 0.0, 0.0); -Scene::~Scene() -{ - // Join Camera Controllers - for (auto camController : m_cameraControllers) - { - camController->end(); - m_threadMap.at(camController->getName()).join(); - } + std::shared_ptr<Camera> debugCam = std::make_shared<Camera>(); + debugCam->setPosition(0.0, 4.0, -30.0); + debugCam->setFocalPoint(0.0, 0.0, 0.0); + + m_cameras["default"] = defaultCam; + m_cameras["debug"] = debugCam; + setActiveCamera("default"); } bool @@ -77,11 +76,8 @@ Scene::initialize() // Build the compute graph buildTaskGraph(); - // Opportunity for external configuration - if (m_postTaskGraphConfigureCallback != nullptr) - { - m_postTaskGraphConfigureCallback(this); - } + // Opportunity for user configuration + this->postEvent(Event(EventType::Configure)); // Then init initTaskGraph(); @@ -98,6 +94,7 @@ Scene::buildTaskGraph() // Clear the compute graph of all nodes/edges except source+sink m_taskGraph->clear(); + m_taskGraph->addEdge(m_taskGraph->getSource(), m_taskGraph->getSink()); // Setup all SceneObject compute graphs (and segment the rigid bodies) std::list<std::shared_ptr<SceneObject>> rigidBodies; @@ -140,7 +137,7 @@ Scene::buildTaskGraph() auto physXUpdate = m_taskGraph->addFunction("PhysXUpdate", [&]() { auto physxScene = RigidBodyWorld::getInstance()->m_Scene; - // TODO: update the time step, split into two steps, collide and advance + // \todo: update the time step, split into two steps, collide and advance physxScene->simulate(RigidBodyWorld::getInstance()->getTimeStep()); physxScene->fetchResults(true); }); @@ -196,22 +193,23 @@ Scene::initTaskGraph() m_taskGraphController->initialize(); } -void -Scene::launchModules() -{ - // Start Camera Controller (asynchronous) - for (auto camController : m_cameraControllers) - { - m_threadMap[camController->getName()] = std::thread([camController] { camController->start(); }); - } -} - bool Scene::isObjectRegistered(const std::string& sceneObjectName) const { return m_sceneObjectsMap.find(sceneObjectName) != m_sceneObjectsMap.end(); } +void +Scene::setEnableTaskTiming(bool enabled) +{ + m_config->taskTimingEnabled = enabled; + // If user wants to benchmark, tell all the nodes to time themselves + for (std::shared_ptr<TaskNode> node : m_taskGraph->getNodes()) + { + node->m_enableTiming = m_config->taskTimingEnabled; + } +} + const std::vector<std::shared_ptr<SceneObject>> Scene::getSceneObjects() const { @@ -225,12 +223,6 @@ Scene::getSceneObjects() const return v; } -const std::vector<std::shared_ptr<SceneObjectControllerBase>> -Scene::getSceneObjectControllers() const -{ - return m_objectControllers; -} - std::shared_ptr<SceneObject> Scene::getSceneObject(const std::string& sceneObjectName) const { @@ -365,45 +357,9 @@ Scene::removeLight(const std::string& lightName) } void -Scene::setGlobalIBLProbe(std::shared_ptr<IBLProbe> newIBLProbe) -{ - m_globalIBLProbe = newIBLProbe; -} - -std::shared_ptr<IBLProbe> -Scene::getGlobalIBLProbe() -{ - return m_globalIBLProbe; -} - -const std::string& -Scene::getName() const -{ - return m_name; -} - -std::shared_ptr<Camera> -Scene::getCamera() const -{ - return m_camera; -} - -std::shared_ptr<CollisionGraph> -Scene::getCollisionGraph() const -{ - return m_collisionGraph; -} - -void -Scene::addObjectController(std::shared_ptr<SceneObjectControllerBase> controller) -{ - m_objectControllers.push_back(controller); -} - -void -Scene::addCameraController(std::shared_ptr<CameraController> camController) +Scene::addController(std::shared_ptr<TrackingDeviceControl> controller) { - m_cameraControllers.push_back(camController); + m_trackingControllers.push_back(controller); } void @@ -452,7 +408,7 @@ Scene::advance(const double dt) } // Update objects controlled by the device controllers - for (auto controller : this->getSceneObjectControllers()) + for (auto controller : this->getControllers()) { controller->updateControlledObjects(); } @@ -463,13 +419,13 @@ Scene::advance(const double dt) m_taskGraphController->execute(); // Apply updated forces on device - for (auto controller : this->getSceneObjectControllers()) + for (auto controller : this->getControllers()) { controller->applyForces(); } // Set the trackers of the scene object controllers to out-of-date - for (auto controller : this->getSceneObjectControllers()) + for (auto controller : this->getControllers()) { controller->setTrackerToOutOfDate(); } @@ -523,12 +479,12 @@ Scene::getElapsedTime(const std::string& stepName) const void Scene::lockComputeTimes() { - computeTimesLock->lock(); + m_computeTimesLock->lock(); } void Scene::unlockComputeTimes() { - computeTimesLock->unlock(); + m_computeTimesLock->unlock(); } } // imstk diff --git a/Source/Scene/imstkScene.h b/Source/Scene/imstkScene.h index 227d2a578229d2a24211a595384cfdfb03fe471d..bfb90c28d763a078b74c8bff16b3b51b72bce4d3 100644 --- a/Source/Scene/imstkScene.h +++ b/Source/Scene/imstkScene.h @@ -21,8 +21,9 @@ #pragma once +#include "imstkEventObject.h" + #include <atomic> -#include <functional> #include <string> #include <thread> #include <unordered_map> @@ -36,9 +37,9 @@ class CollisionGraph; class IBLProbe; class Light; class SceneObject; -class SceneObjectControllerBase; class TaskGraph; class TaskGraphController; +class TrackingDeviceControl; class VisualModel; namespace ParallelUtils { class SpinLock; } @@ -79,21 +80,14 @@ struct SceneConfig /// /// \brief /// -class Scene +class Scene : public EventObject { template<class T> using NamedMap = std::unordered_map<std::string, std::shared_ptr<T>>; public: - /// - /// \brief Constructor - /// explicit Scene(const std::string& name, std::shared_ptr<SceneConfig> config = std::make_shared<SceneConfig>()); - - /// - /// \brief Destructor - /// - ~Scene(); + virtual ~Scene() override = default; public: /// @@ -111,11 +105,6 @@ public: /// void initTaskGraph(); - /// - /// \brief Launch camera controller and other scene specific modules that need to run independently - /// - void launchModules(); - /// /// \brief Reset the scene /// @@ -137,6 +126,12 @@ public: /// bool isObjectRegistered(const std::string& sceneObjectName) const; + /// + /// \brief If true, tasks will be time and a table produced + /// every scene advance of the times + /// + void setEnableTaskTiming(bool enabled); + /// /// \brief Return a vector of shared pointers to the scene objects /// NOTE: A separate list might be efficient as this is called runtime @@ -152,7 +147,7 @@ public: /// /// \brief Get the scene object controllers /// - const std::vector<std::shared_ptr<SceneObjectControllerBase>> getSceneObjectControllers() const; + const std::vector<std::shared_ptr<TrackingDeviceControl>> getControllers() const { return m_trackingControllers; } /// /// \brief Get a scene object of a specific name @@ -194,13 +189,13 @@ public: /// /// \brief Add/remove lights from the scene /// - void setGlobalIBLProbe(std::shared_ptr<IBLProbe> newIBLProbe); - std::shared_ptr<IBLProbe> getGlobalIBLProbe(); + void setGlobalIBLProbe(std::shared_ptr<IBLProbe> newIBLProbe) { m_globalIBLProbe = newIBLProbe; } + std::shared_ptr<IBLProbe> getGlobalIBLProbe() { return m_globalIBLProbe; } /// /// \brief Get the name of the scene /// - const std::string& getName() const; + const std::string& getName() const { return m_name; } /// /// \brief Get the computational graph of the scene @@ -210,22 +205,67 @@ public: /// /// \brief Get the camera for the scene /// - std::shared_ptr<Camera> getCamera() const; + std::shared_ptr<Camera> getActiveCamera() const { return m_activeCamera; } /// - /// \brief Return the collision graph + /// \brief Get the name of the camera, if it exists /// - std::shared_ptr<CollisionGraph> getCollisionGraph() const; + std::string getCameraName(std::shared_ptr<Camera> cam) const + { + auto i = std::find_if(m_cameras.begin(), m_cameras.end(), + [&cam](const NamedMap<Camera>::value_type& j) { return j.second == cam; }); + if (i != m_cameras.end()) + { + return i->first; + } + else + { + return ""; + } + } /// - /// \brief Add objects controllers + /// \brief Get camera by name /// - void addObjectController(std::shared_ptr<SceneObjectControllerBase> controller); + std::shared_ptr<Camera> getCamera(std::string name) const + { + auto i = m_cameras.find(name); + if (i != m_cameras.end()) + { + return i->second; + } + else + { + return nullptr; + } + } + + /// + /// \brief Set the camera for the scene + /// + void addCamera(std::string name, std::shared_ptr<Camera> cam) { m_cameras[name] = cam; } + + /// + /// \brief Set the active camera by name + /// + void setActiveCamera(std::string name) + { + auto i = m_cameras.find(name); + if (i != m_cameras.end()) + { + m_activeCamera = m_cameras[name]; + } + } + + /// + /// \brief Return the collision graph + /// + std::shared_ptr<CollisionGraph> getCollisionGraph() const { return m_collisionGraph; } /// /// \brief Add objects controllers /// - void addCameraController(std::shared_ptr<CameraController> camController); + void addController(std::shared_ptr<TrackingDeviceControl> controller); /// /// \brief @@ -263,11 +303,6 @@ public: /// void unlockComputeTimes(); - /// - /// \brief Called after compute graph is built, but before initialized - /// - void setTaskGraphConfigureCallback(std::function<void(Scene*)> callback) { this->m_postTaskGraphConfigureCallback = callback; } - /// /// \brief Get the configuration /// @@ -283,18 +318,17 @@ protected: NamedMap<Light> m_lightsMap; std::shared_ptr<IBLProbe> m_globalIBLProbe = nullptr; - std::shared_ptr<Camera> m_camera = std::make_shared<Camera>(); + NamedMap<Camera> m_cameras; + std::shared_ptr<Camera> m_activeCamera; - std::shared_ptr<CollisionGraph> m_collisionGraph = nullptr; - std::vector<std::shared_ptr<SceneObjectControllerBase>> m_objectControllers; ///> List of object controllers - std::vector<std::shared_ptr<CameraController>> m_cameraControllers; ///> List of camera controllers - std::unordered_map<std::string, std::thread> m_threadMap; ///> + std::shared_ptr<CollisionGraph> m_collisionGraph; + std::vector<std::shared_ptr<TrackingDeviceControl>> m_trackingControllers; ///> List of object controllers - std::shared_ptr<TaskGraph> m_taskGraph = nullptr; ///> Computational graph - std::shared_ptr<TaskGraphController> m_taskGraphController = nullptr; ///> Controller for the computational graph + std::shared_ptr<TaskGraph> m_taskGraph; ///> Computational graph + std::shared_ptr<TaskGraphController> m_taskGraphController = nullptr; ///> Controller for the computational graph std::function<void(Scene*)> m_postTaskGraphConfigureCallback = nullptr; - std::shared_ptr<ParallelUtils::SpinLock> computeTimesLock = nullptr; + std::shared_ptr<ParallelUtils::SpinLock> m_computeTimesLock; std::unordered_map<std::string, double> m_nodeComputeTimes; ///> Map of ComputeNode names to elapsed times for benchmarking double m_fps = 0.0; diff --git a/Source/Scene/imstkSphObjectCollisionPair.cpp b/Source/Scene/imstkSphObjectCollisionPair.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c684ff84384b54887e6b5d4b6e789a2e9b5ac6e0 --- /dev/null +++ b/Source/Scene/imstkSphObjectCollisionPair.cpp @@ -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. + +=========================================================================*/ + +#include "imstkSphObjectCollisionPair.h" +#include "imstkCDObjectFactory.h" +#include "imstkCollisionData.h" +#include "imstkImplicitGeometryToPointSetCD.h" +#include "imstkSPHCollisionHandling.h" +#include "imstkSPHModel.h" +#include "imstkSPHObject.h" +#include "imstkTaskGraph.h" +#include "imstkImplicitGeometry.h" + +namespace imstk +{ +// Pbd Collision will be tested before any step of pbd, then resolved after the solve steps of the two objects +SphObjectCollisionPair::SphObjectCollisionPair(std::shared_ptr<SPHObject> obj1, std::shared_ptr<CollidingObject> obj2, + CollisionDetection::Type cdType) : CollisionPair(obj1, obj2) +{ + std::shared_ptr<Geometry> colGeometry = obj2->getCollidingGeometry(); + std::shared_ptr<ImplicitGeometry> implicitGeom = std::dynamic_pointer_cast<ImplicitGeometry>(colGeometry); + if (implicitGeom == nullptr) + { + LOG(WARNING) << "Geometry, " << colGeometry->getName() << " not an ImplicitGeometry"; + return; + } + + std::shared_ptr<SPHModel> dynaModel = obj1->getSPHModel(); + + // Collision should happen after positions and velocities are computed + m_taskNodeInputs.first.push_back(obj1->getUpdateGeometryNode()); + m_taskNodeInputs.second.push_back(obj2->getUpdateNode()); + + m_taskNodeOutputs.first.push_back(obj1->getTaskGraph()->getSink()); + m_taskNodeOutputs.second.push_back(obj2->getTaskGraph()->getSink()); + + // Setup the CD + m_colData = std::make_shared<CollisionData>(); + setCollisionDetection(makeCollisionDetectionObject(cdType, obj1->getCollidingGeometry(), obj2->getCollidingGeometry(), m_colData)); + + // Setup the handler + std::shared_ptr<SPHCollisionHandling> ch = std::make_shared<SPHCollisionHandling>(CollisionHandling::Side::B, m_colData, obj1); + ch->setDetection(std::dynamic_pointer_cast<ImplicitGeometryToPointSetCD>(getCollisionDetection())); + setCollisionHandlingB(ch); +} +} \ No newline at end of file diff --git a/Source/Scene/imstkSphObjectCollisionPair.h b/Source/Scene/imstkSphObjectCollisionPair.h new file mode 100644 index 0000000000000000000000000000000000000000..a25548008fcd68fa5fb8fd9352875b7f3d8ded4a --- /dev/null +++ b/Source/Scene/imstkSphObjectCollisionPair.h @@ -0,0 +1,44 @@ +/*========================================================================= + +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 "imstkCollisionPair.h" +#include "imstkCollisionDetection.h" + +namespace imstk +{ +class SPHObject; + +/// +/// \class SphObjectCollisionPair +/// +/// \brief This class defines where collision should happen bsetween an SphObject and colliding object +/// +class SphObjectCollisionPair : public CollisionPair +{ +public: + SphObjectCollisionPair(std::shared_ptr<SPHObject> obj1, std::shared_ptr<CollidingObject> obj2, + CollisionDetection::Type cdType = CollisionDetection::Type::PointSetToImplicit); + + virtual ~SphObjectCollisionPair() override = default; +}; +} \ No newline at end of file diff --git a/Source/SceneEntities/Camera/imstkCamera.cpp b/Source/SceneEntities/Camera/imstkCamera.cpp deleted file mode 100644 index c095a5da4f2bc1dadfe013b442583bdc9234525b..0000000000000000000000000000000000000000 --- a/Source/SceneEntities/Camera/imstkCamera.cpp +++ /dev/null @@ -1,101 +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 <memory> - -#include "imstkCamera.h" - -#include <g3log/g3log.hpp> - -namespace imstk -{ -const Vec3d& -Camera::getPosition() const -{ - return m_position; -} - -void -Camera::setPosition(const Vec3d& p) -{ - m_position = p; -} - -void -Camera::setPosition(const double& x, - const double& y, - const double& z) -{ - m_position = Vec3d(x, y, z); -} - -const Vec3d& -Camera::getFocalPoint() const -{ - return m_focalPoint; -} - -void -Camera::setFocalPoint(const Vec3d& p) -{ - m_focalPoint = p; -} - -void -Camera::setFocalPoint(const double& x, - const double& y, - const double& z) -{ - m_focalPoint = Vec3d(x, y, z); -} - -const Vec3d& -Camera::getViewUp() const -{ - return m_viewUp; -} - -void -Camera::setViewUp(const Vec3d& v) -{ - m_viewUp = v; -} - -void -Camera::setViewUp(const double& x, - const double& y, - const double& z) -{ - m_viewUp = Vec3d(x, y, z).normalized(); -} - -const double& -Camera::getFieldOfView() const -{ - return m_fieldOfView; -} - -void -Camera::setFieldOfView(const double& fov) -{ - m_fieldOfView = fov; -} -} // imstk diff --git a/Source/SceneEntities/Camera/imstkCamera.h b/Source/SceneEntities/Camera/imstkCamera.h index 382157205a9f89e8b1d2c7c13b9fe9d0f562f919..68c661357c67abe04074d88dddcc8ad6ba9a157a 100644 --- a/Source/SceneEntities/Camera/imstkCamera.h +++ b/Source/SceneEntities/Camera/imstkCamera.h @@ -9,7 +9,7 @@ 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 + 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, @@ -21,90 +21,206 @@ #pragma once -#include <string> -#include <memory> - #include "imstkMath.h" namespace imstk { +/// +/// \brief Produces a transform pointing forward towards target from position, oriented by up +/// +static Mat4d +lookAt(const Vec3d& pos, const Vec3d& target, const Vec3d& up) +{ + Mat4d results = Mat4d::Identity(); + Mat3d R; + R.col(2) = (pos - target).normalized(); + R.col(0) = up.cross(R.col(2)).normalized(); + R.col(1) = R.col(2).cross(R.col(0)); + results.topLeftCorner<3, 3>() = R.transpose(); + results.topRightCorner<3, 1>() = -R.transpose() * pos; + results(3, 3) = 1.0; + + return results; +} + +/// +/// \brief Produces a perpsective transformation matrix +/// +//static Mat4d +//perspective(const double fovY, const double aspect, const double nearZ, const double farZ) +//{ +// Mat4d results; +// results.setZero(); +// const double theta = fovY * 0.5; +// const double range = (farZ - nearZ); +// const double invTan = 1.0 / tan(theta); +// +// results(0, 0) = invTan / aspect; +// results(1, 1) = invTan; +// results(2, 2) = -(nearZ + farZ) / range; +// results(3, 2) = -1.0; +// results(2, 3) = -2.0 * nearZ * farZ / range; +// return results; +//} + /// /// \class Camera /// -/// \brief Generic camera class +/// \brief The base camera class defines a lookat camera /// class Camera { public: + Camera() = default; + virtual ~Camera() = default; + +public: + /// + /// \brief Get camera view matrix + /// \returns Camera view matrix reference + /// + Mat4d& getView() { return m_view; } + + /// + /// \brief Get the inverse view matrix + /// + const Mat4d& getInvView() { return m_invView; } + + /// + /// \brief Set the camera view matrix + /// + void setView(const Mat4d& view) + { + m_viewModified = false; + m_view = view; + } + + /// + /// \brief Get camera projection matrix /// - /// \brief Default contructor + //const Mat4d& getProj() { return m_proj; } + + /// + /// \brief Set camera projection matrix /// - Camera() {} + //void setProj(const Mat4d& proj) { m_proj = proj; } /// - /// \brief Default destructor + /// \brief Gets the field of view + /// \returns vertical field of view in degrees + /// + const double getFieldOfView() const { return m_fieldOfView; } + /// - ~Camera() = default; + /// \brief Sets the field of view + /// \param vertical field of view in degrees + /// + void setFieldOfView(const double fov) + { + m_fieldOfView = fov; + //m_projModified = true; + } + + virtual void update() + { + if (m_viewModified) + { + m_view = lookAt(m_position, m_focalPoint, m_viewUp); + m_invView = m_view.inverse(); + m_viewModified = false; + } + /*if (m_projModified) + { + m_proj = perspective(); + }*/ + } +public: /// /// \brief Gets the camera position /// \returns camera position /// - const Vec3d& getPosition() const; + const Vec3d& getPosition() const { return m_position; } /// /// \brief Sets the camera position /// - void setPosition(const Vec3d& p); - void setPosition(const double& x, - const double& y, - const double& z); + void setPosition(const Vec3d& pos) + { + m_position = pos; + m_viewModified = true; + } + + void setPosition(const double x, + const double y, + const double z) + { + setPosition(Vec3d(x, y, z)); + } /// /// \brief Returns the focal point /// The focal point is the point that the camera points to /// \returns Focal point position /// - const Vec3d& getFocalPoint() const; + const Vec3d& getFocalPoint() const { return m_focalPoint; } /// /// \brief Sets the focal point /// - void setFocalPoint(const Vec3d& p); - void setFocalPoint(const double& x, - const double& y, - const double& z); + void setFocalPoint(const Vec3d& focalPt) + { + m_focalPoint = focalPt; + m_viewModified = true; + } + + void setFocalPoint(const double x, + const double y, + const double z) + { + setFocalPoint(Vec3d(x, y, z)); + } /// /// \brief Get the up vector /// \returns up vector of camera /// - const Vec3d& getViewUp() const; + const Vec3d& getViewUp() const { return m_viewUp; } /// /// \brief Set the up vector /// - void setViewUp(const Vec3d& v); - void setViewUp(const double& x, - const double& y, - const double& z); - /// - /// \brief Gets the field of view - /// \returns vertical field of view in degrees - /// - const double& getFieldOfView() const; + void setViewUp(const Vec3d& up) + { + m_viewUp = up.normalized(); + m_viewModified = true; + } - /// - /// \brief Sets the field of view - /// params fov vertical field of view in degrees - /// - void setFieldOfView(const double& fov); + void setViewUp(const double x, + const double y, + const double z) + { + setViewUp(Vec3d(x, y, z)); + } protected: + // Base camera values + Mat4d m_view = Mat4d::Identity(); ///> Actual view matrix used + Mat4d m_invView = Mat4d::Identity(); ///> Inverse is often needed so we maintain it + //Mat4d m_proj; + bool m_viewModified = true; +//bool m_projModified = true; - Vec3d m_position = Vec3d(0, 2, 5); ///> camera position - Vec3d m_focalPoint = WORLD_ORIGIN; ///> camera focal point - Vec3d m_viewUp = UP_VECTOR; ///> camera up vector - double m_fieldOfView = 60; ///> field of view in degrees +protected: + // Base projection parameters + double m_fieldOfView = 40.0; ///> field of view in degrees + double m_nearZ = 0.01; ///> near plane of the camera + double m_farZ = 1000.0; ///> far plane of the camera + +protected: + // Lookat camera parameters + Vec3d m_position = Vec3d(0, 2, 5); ///> camera position + Vec3d m_focalPoint = WORLD_ORIGIN; ///> camera focal point + Vec3d m_viewUp = UP_VECTOR; ///> camera up vector }; -} // imstk +} diff --git a/Source/SceneEntities/Lights/imstkIBLProbe.cpp b/Source/SceneEntities/Lights/imstkIBLProbe.cpp index de9840747232300769f5ec58f4daa3f0f2a57a2b..9c8b5e1c67ed6602a3d373478a66608111211916 100644 --- a/Source/SceneEntities/Lights/imstkIBLProbe.cpp +++ b/Source/SceneEntities/Lights/imstkIBLProbe.cpp @@ -20,9 +20,23 @@ =========================================================================*/ #include "imstkIBLProbe.h" +#include "imstkTexture.h" namespace imstk { +IBLProbe::IBLProbe(std::string irradianceCubemapPath, + std::string radianceCubemapPath, std::string brdfLUTPath) : + m_irradianceCubemapPath(irradianceCubemapPath), + m_radianceCubemapPath(radianceCubemapPath), + m_brdfLUTPath(brdfLUTPath), + m_irradianceCubemapTexture(std::make_shared<Texture>(irradianceCubemapPath, + Texture::Type::IrradianceCubeMap)), + m_radianceCubemapTexture(std::make_shared<Texture>(radianceCubemapPath, + Texture::Type::RadianceCubeMap)), + m_brdfLUTTexture(std::make_shared<Texture>(brdfLUTPath, Texture::Type::BRDF_LUT)) +{ +} + std::shared_ptr<Texture> IBLProbe::getIrradianceCubemapTexture() { diff --git a/Source/SceneEntities/Lights/imstkIBLProbe.h b/Source/SceneEntities/Lights/imstkIBLProbe.h index e1ad0ed9b04f21044be0ec6d9b75f4673a7b750c..e456b53c60233a0411c53d444143d49bb33f0e5f 100644 --- a/Source/SceneEntities/Lights/imstkIBLProbe.h +++ b/Source/SceneEntities/Lights/imstkIBLProbe.h @@ -21,12 +21,13 @@ #pragma once +#include <memory> #include <string> -#include "imstkTexture.h" - namespace imstk { +class Texture; + /// /// \class IBLProbe /// @@ -48,16 +49,7 @@ public: /// \param brdfLUTPath path to BRDF LUT (shouldn't be .dds) /// IBLProbe(std::string irradianceCubemapPath, - std::string radianceCubemapPath, - std::string brdfLUTPath) : - m_irradianceCubemapPath(irradianceCubemapPath), - m_radianceCubemapPath(radianceCubemapPath), - m_brdfLUTPath(brdfLUTPath), - m_irradianceCubemapTexture(std::make_shared<Texture>(irradianceCubemapPath, - Texture::Type::IrradianceCubeMap)), - m_radianceCubemapTexture(std::make_shared<Texture>(radianceCubemapPath, - Texture::Type::RadianceCubeMap)), - m_brdfLUTTexture(std::make_shared<Texture>(brdfLUTPath, Texture::Type::BRDF_LUT)) {} + std::string radianceCubemapPath, std::string brdfLUTPath); /// \brief TODO std::shared_ptr<Texture> getIrradianceCubemapTexture(); diff --git a/Source/SceneEntities/Lights/imstkLight.cpp b/Source/SceneEntities/Lights/imstkLight.cpp index 4f522a8407c608217b42366ddc241f8ad4d2c806..ee9dea0c8b1828510ff7dae9051579f3b64c91d6 100644 --- a/Source/SceneEntities/Lights/imstkLight.cpp +++ b/Source/SceneEntities/Lights/imstkLight.cpp @@ -20,8 +20,7 @@ =========================================================================*/ #include "imstkLight.h" - -#include <g3log/g3log.hpp> +#include "imstkLogger.h" namespace imstk { diff --git a/Source/SceneEntities/Lights/imstkLight.h b/Source/SceneEntities/Lights/imstkLight.h index 1d46b74e8c3f07d9deb5fcc3c5ac31d9919e5ae4..c0e5d65878a4f973642124a9d8dd3343804f189a 100644 --- a/Source/SceneEntities/Lights/imstkLight.h +++ b/Source/SceneEntities/Lights/imstkLight.h @@ -21,13 +21,12 @@ #pragma once -#include <string> - -// imstk #include "imstkMath.h" #include "imstkColor.h" #include "imstkSceneEntity.h" +#include <string> + namespace imstk { /// @@ -48,6 +47,8 @@ enum class LightType class Light : public SceneEntity { public: + virtual ~Light() override = default; + /// /// \brief Returns the type of light (see imstk::LightType) /// @@ -113,11 +114,10 @@ public: /// /// \brief Set the light name /// - void setName(const std::string& name) { m_name = name; }; - void setName(const std::string&& name) { m_name = std::move(name); }; + void setName(std::string name) { m_name = name; }; protected: - explicit Light(const std::string& name, const LightType& type) : m_name(name), m_type(type), SceneEntity() {}; + explicit Light(const std::string& name, const LightType& type) : SceneEntity(), m_name(name), m_type(type) {}; // properties with defaults float m_intensity = 1.; @@ -150,6 +150,8 @@ public: this->setFocalPoint(-1, -1, -1); }; + virtual ~DirectionalLight() override = default; + /// /// \brief Turn shadows on /// @@ -159,13 +161,19 @@ public: /// \brief Center point for shadow projection /// Sets the shadow map center to this position /// - void setShadowCenter(Vec3d center) { m_shadowCenter = Vec3f((float)center[0], (float)center[1], (float)center[2]); }; + void setShadowCenter(const Vec3d& center) { m_shadowCenter = center.cast<float>(); }; /// /// \brief Range for shadows /// A smaller range results in a denser shadow map /// - void setShadowRange(const double range) { m_shadowRange = (float)range; }; + void setShadowRange(const double range) { m_shadowRange = static_cast<float>(range); }; + + /// + /// \brief Direction of the light + /// + void setDirection(const Vec3d& dir) { setFocalPoint(dir); } + void setDirection(const double x, const double y, const double z) { setFocalPoint(Vec3d(x, y, z)); } protected: friend class VulkanRenderer; @@ -194,6 +202,8 @@ public: /// explicit PointLight(const std::string& name, const LightType& type = LightType::Point) : Light(name, type) {}; + virtual ~PointLight() override = default; + /// /// \brief Get the cone angle /// @@ -244,6 +254,8 @@ public: m_coneAngle = 10.; }; + virtual ~SpotLight() override = default; + /// /// \brief Get the spotlight angle in degrees /// diff --git a/Source/SceneEntities/Loader/imstkVisualObjectImporter.cpp b/Source/SceneEntities/Loader/imstkVisualObjectImporter.cpp index 3e138b610210623a8ee4770ec5c2505c62c26389..0092ed0bc1db2dda11fa78f193d038b6ce18b402 100644 --- a/Source/SceneEntities/Loader/imstkVisualObjectImporter.cpp +++ b/Source/SceneEntities/Loader/imstkVisualObjectImporter.cpp @@ -20,17 +20,15 @@ =========================================================================*/ #include "imstkVisualObjectImporter.h" +#include "imstkAssimpMeshIO.h" +#include "imstkLogger.h" #include "imstkRenderMaterial.h" - -#include "assimp/Importer.hpp" -#include "assimp/mesh.h" -#include "assimp/scene.h" -#include "assimp/postprocess.h" - +#include "imstkSceneObject.h" #include "imstkSurfaceMesh.h" -#include "imstkAssimpMeshIO.h" +#include "imstkVisualModel.h" -#include "imstkLogger.h" +#include <assimp/Importer.hpp> +#include <assimp/scene.h> namespace imstk { diff --git a/Source/SceneEntities/Loader/imstkVisualObjectImporter.h b/Source/SceneEntities/Loader/imstkVisualObjectImporter.h index e6579f26bfbabd38666cebc0c9603443390e1cef..c3a5fc390c19b6625e98da9f42e313dfe9a729c2 100644 --- a/Source/SceneEntities/Loader/imstkVisualObjectImporter.h +++ b/Source/SceneEntities/Loader/imstkVisualObjectImporter.h @@ -21,18 +21,13 @@ #pragma once -#include <memory> -#include <fstream> -#include <string> -#include <initializer_list> - #include "imstkTexture.h" -#include "imstkSceneObject.h" #include "imstkMath.h" namespace imstk { class RenderMaterial; +class SceneObject; /// /// \class VisualObjectImporter @@ -60,7 +55,7 @@ public: /// textures are converted to production-ready formats such as .dds. /// \returns Visual object /// - static std::shared_ptr<VisualObject> importVisualObject( + static std::shared_ptr<SceneObject> importVisualObject( const std::string& objName, const std::string& modelFilePath, const std::string& textureFolderPath, diff --git a/Source/SceneEntities/Objects/imstkAnimationObject.cpp b/Source/SceneEntities/Objects/imstkAnimationObject.cpp index 05f3e455a3958da2bcbaf91fb25917162d819819..a6c408129c89a7cdc7b3d6873bb33d7ab4564e72 100644 --- a/Source/SceneEntities/Objects/imstkAnimationObject.cpp +++ b/Source/SceneEntities/Objects/imstkAnimationObject.cpp @@ -20,7 +20,6 @@ =========================================================================*/ #include "imstkAnimationObject.h" -#include "imstkAnimationModel.h" namespace imstk { diff --git a/Source/SceneEntities/Objects/imstkCollidingObject.cpp b/Source/SceneEntities/Objects/imstkCollidingObject.cpp index 39560d82a9fa651b6f45a80af711a34de92c39bd..b6b93acaf3943a0a1f28fd62b2a136b00df08bfc 100644 --- a/Source/SceneEntities/Objects/imstkCollidingObject.cpp +++ b/Source/SceneEntities/Objects/imstkCollidingObject.cpp @@ -40,14 +40,14 @@ CollidingObject::initialize() return true; } -const std::shared_ptr<Geometry>& +std::shared_ptr<Geometry> CollidingObject::getCollidingGeometry() const { return m_collidingGeometry; } void -CollidingObject::setCollidingGeometry(const std::shared_ptr<Geometry>& geometry) +CollidingObject::setCollidingGeometry(std::shared_ptr<Geometry> geometry) { m_collidingGeometry = geometry; } diff --git a/Source/SceneEntities/Objects/imstkCollidingObject.h b/Source/SceneEntities/Objects/imstkCollidingObject.h index abdbf60e11a6ee6a70953ab2bb464f63b94520e5..a757fabb195ee5584fac7b3508c259cb881047ed 100644 --- a/Source/SceneEntities/Objects/imstkCollidingObject.h +++ b/Source/SceneEntities/Objects/imstkCollidingObject.h @@ -23,7 +23,6 @@ #include "imstkSceneObject.h" #include "imstkMath.h" -#include <unordered_map> namespace imstk { @@ -50,8 +49,8 @@ public: /// /// \brief /// - const std::shared_ptr<Geometry>& getCollidingGeometry() const; - void setCollidingGeometry(const std::shared_ptr<Geometry>& geometry); + std::shared_ptr<Geometry> getCollidingGeometry() const; + void setCollidingGeometry(std::shared_ptr<Geometry> geometry); /// /// \brief Get the master geometry diff --git a/Source/SceneEntities/Objects/imstkDynamicObject.cpp b/Source/SceneEntities/Objects/imstkDynamicObject.cpp index c6bf8e64caa458d01b2e9b98fd575f00602f7335..9dc6f2d00db19fda3b56a9cf4f5cca0a5a5abb9e 100644 --- a/Source/SceneEntities/Objects/imstkDynamicObject.cpp +++ b/Source/SceneEntities/Objects/imstkDynamicObject.cpp @@ -42,12 +42,7 @@ DynamicObject::getNumOfDOF() const void DynamicObject::updateGeometries() { - m_dynamicalModel->updatePhysicsGeometry(); - - if (m_physicsToCollidingGeomMap) - { - m_physicsToCollidingGeomMap->apply(); - } + updatePhysicsGeometry(); if (m_updateVisualFromPhysicsGeometry) { diff --git a/Source/SceneEntities/Objects/imstkDynamicObject.h b/Source/SceneEntities/Objects/imstkDynamicObject.h index 58a6bb7930dc3030c91312c81c700b06106f8181..a08060780349f008bbdf4ddeb0be55c845416fb6 100644 --- a/Source/SceneEntities/Objects/imstkDynamicObject.h +++ b/Source/SceneEntities/Objects/imstkDynamicObject.h @@ -84,7 +84,7 @@ public: /// /// \brief Update only the physics geometry and apply collision map /// - void updatePhysicsGeometry(); + virtual void updatePhysicsGeometry(); /// /// \brief Initialize the scene object @@ -98,7 +98,7 @@ public: protected: /// - /// \brief Setup connectivity of compute graph + /// \brief Setup connectivity of task graph /// virtual void initGraphEdges(std::shared_ptr<TaskNode> source, std::shared_ptr<TaskNode> sink) override; diff --git a/Source/SceneEntities/Objects/imstkFeDeformableObject.cpp b/Source/SceneEntities/Objects/imstkFeDeformableObject.cpp index d49510a0a844bf161759b65d0e48874f1c08a1db..ef34448492e5faed86276541a79eda0b5728d071 100644 --- a/Source/SceneEntities/Objects/imstkFeDeformableObject.cpp +++ b/Source/SceneEntities/Objects/imstkFeDeformableObject.cpp @@ -40,4 +40,11 @@ FeDeformableObject::initialize() return true; } + +std::shared_ptr<FEMDeformableBodyModel> +FeDeformableObject::getFEMModel() +{ + m_femModel = std::dynamic_pointer_cast<FEMDeformableBodyModel>(m_dynamicalModel); + return m_femModel; +} } // imstk diff --git a/Source/SceneEntities/Objects/imstkFeDeformableObject.h b/Source/SceneEntities/Objects/imstkFeDeformableObject.h index 26c2fbc7475063dc9a7e12d04bb718d9732c2eea..1cef4ac8e665a9428d971e9ed5862bde9eadfdcd 100644 --- a/Source/SceneEntities/Objects/imstkFeDeformableObject.h +++ b/Source/SceneEntities/Objects/imstkFeDeformableObject.h @@ -21,10 +21,6 @@ #pragma once -#include <memory> -#include <string> - -// imstk #include "imstkDynamicObject.h" #include "imstkMath.h" @@ -51,7 +47,7 @@ public: /// bool initialize() override; - std::shared_ptr<FEMDeformableBodyModel> getFEMModel() const { return m_femModel; } + std::shared_ptr<FEMDeformableBodyModel> getFEMModel(); protected: std::shared_ptr<FEMDeformableBodyModel> m_femModel = nullptr; diff --git a/Source/Solvers/imstkLinearSolver.cpp b/Source/SceneEntities/Objects/imstkLevelSetDeformableObject.cpp similarity index 57% rename from Source/Solvers/imstkLinearSolver.cpp rename to Source/SceneEntities/Objects/imstkLevelSetDeformableObject.cpp index 88e14c0714b70b29a5bec3aec7dade6a5a6f3e51..53297f534a40d3b696e8bea9b087fdf98814a058 100644 --- a/Source/Solvers/imstkLinearSolver.cpp +++ b/Source/SceneEntities/Objects/imstkLevelSetDeformableObject.cpp @@ -19,29 +19,33 @@ =========================================================================*/ -#include "imstkLinearSolver.h" +#include "imstkLevelSetDeformableObject.h" #include "imstkLogger.h" +#include "imstkPbdModel.h" +#include "imstkLevelSetModel.h" namespace imstk { -//template<typename SystemMatrixType> -//LinearSolver<SystemMatrixType>::LinearSolver() : m_linearSystem(nullptr) -//{ -// -//} - -//template<typename SystemMatrixType> -//void -//LinearSolver<SystemMatrixType>::setSystem(std::shared_ptr<LinearSystem<SystemMatrixType>> newSystem) -//{ -// m_linearSystem.reset(); -// m_linearSystem = newSystem; -//} -// -//template<typename SystemMatrixType> -//std::shared_ptr<LinearSystem<SystemMatrixType>> -//LinearSolver<SystemMatrixType>::getSystem() const -//{ -// return m_linearSystem; -//} -} //imstk \ No newline at end of file +std::shared_ptr<LevelSetModel> +LevelSetDeformableObject::getLevelSetModel() +{ + m_levelSetModel = std::dynamic_pointer_cast<LevelSetModel>(m_dynamicalModel); + return m_levelSetModel; +} + +bool +LevelSetDeformableObject::initialize() +{ + m_levelSetModel = std::dynamic_pointer_cast<LevelSetModel>(m_dynamicalModel); + if (m_levelSetModel == nullptr) + { + LOG(FATAL) << "Dynamics pointer cast failure in LevelSetDeformableObject::initialize()"; + return false; + } + + DynamicObject::initialize(); + m_levelSetModel->initialize(); + + return true; +} +} \ No newline at end of file diff --git a/Source/SceneEntities/Objects/imstkLevelSetDeformableObject.h b/Source/SceneEntities/Objects/imstkLevelSetDeformableObject.h new file mode 100644 index 0000000000000000000000000000000000000000..e8aa41d18c77ae15f1571f3311cb3e639573b62e --- /dev/null +++ b/Source/SceneEntities/Objects/imstkLevelSetDeformableObject.h @@ -0,0 +1,62 @@ +/*========================================================================= + + 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 "imstkDynamicObject.h" + +namespace imstk +{ +class LevelSetModel; + +/// +/// \class PbdObject +/// +/// \brief Base class for scene objects that move and/or deform under position +/// based dynamics formulation, implements the PbdModel and PbdSolver +/// +class LevelSetDeformableObject : public DynamicObject +{ +public: + explicit LevelSetDeformableObject(const std::string& name) : DynamicObject(name) + { + m_type = SceneObject::Type::LevelSetDeformable; + } + + LevelSetDeformableObject() = delete; + + virtual ~LevelSetDeformableObject() override = default; + +public: + /// + /// \biref Get the Pbd model of the object + /// + std::shared_ptr<LevelSetModel> getLevelSetModel(); + + /// + /// \brief Initialize the pbd scene object + /// + bool initialize() override; + +protected: + std::shared_ptr<LevelSetModel> m_levelSetModel = nullptr; ///> PBD mathematical model +}; +} // imstk diff --git a/Source/SceneEntities/Objects/imstkPbdObject.cpp b/Source/SceneEntities/Objects/imstkPbdObject.cpp index 731aa243662478c8d175300cbc08b51910aef344..c0b25eb9042469af3e8ae341927e84b7ae21fb24 100644 --- a/Source/SceneEntities/Objects/imstkPbdObject.cpp +++ b/Source/SceneEntities/Objects/imstkPbdObject.cpp @@ -30,7 +30,7 @@ PbdObject::getPbdModel() { m_pbdModel = std::dynamic_pointer_cast<PbdModel>(m_dynamicalModel); return m_pbdModel; -}; +} bool PbdObject::initialize() diff --git a/Source/SceneEntities/Objects/imstkPbdObject.h b/Source/SceneEntities/Objects/imstkPbdObject.h index 0ee18a27ce575a4c5a19b7b5e4d9139fa2964722..d48cae4ca3d4a3e5983e5463ce2ff082d27236ca 100644 --- a/Source/SceneEntities/Objects/imstkPbdObject.h +++ b/Source/SceneEntities/Objects/imstkPbdObject.h @@ -43,7 +43,7 @@ public: PbdObject() = delete; - ~PbdObject() override = default; + virtual ~PbdObject() override = default; public: /// diff --git a/Source/SceneEntities/Objects/imstkRigidObject.cpp b/Source/SceneEntities/Objects/imstkRigidObject.cpp index fa2ebba781ae404919be4cf353ecb80b111c0cd0..887861a650ced49cbc5098fd463742d533222722 100644 --- a/Source/SceneEntities/Objects/imstkRigidObject.cpp +++ b/Source/SceneEntities/Objects/imstkRigidObject.cpp @@ -46,4 +46,11 @@ RigidObject::addForce(const Vec3d& force, const Vec3d& pos, bool wakeup) { m_rigidBodyModel->addForce(force, pos, wakeup); } + +std::shared_ptr<RigidBodyModel> +RigidObject::getRigidBodyModel() +{ + m_rigidBodyModel = std::dynamic_pointer_cast<RigidBodyModel>(m_dynamicalModel); + return m_rigidBodyModel; +} } // imstk diff --git a/Source/SceneEntities/Objects/imstkRigidObject.h b/Source/SceneEntities/Objects/imstkRigidObject.h index eb24b27f24ab84c3a3ec4b9f9703d5ffd29efca8..8383495bfedcfbefe83a11972d1962be37cf6b32 100644 --- a/Source/SceneEntities/Objects/imstkRigidObject.h +++ b/Source/SceneEntities/Objects/imstkRigidObject.h @@ -40,7 +40,7 @@ public: m_type = Type::Rigid; } - ~RigidObject() = default; + virtual ~RigidObject() = default; public: /// @@ -53,7 +53,7 @@ public: /// void addForce(const Vec3d& force, const Vec3d& pos, bool wakeup = true); - std::shared_ptr<RigidBodyModel> getRigidBodyModel() const { return m_rigidBodyModel; } + std::shared_ptr<RigidBodyModel> getRigidBodyModel(); protected: std::shared_ptr<RigidBodyModel> m_rigidBodyModel; diff --git a/Source/SceneEntities/Objects/imstkRigidObject2.cpp b/Source/SceneEntities/Objects/imstkRigidObject2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c907f9e6039090901c5b0c75506f94cf163e6f26 --- /dev/null +++ b/Source/SceneEntities/Objects/imstkRigidObject2.cpp @@ -0,0 +1,77 @@ +/*========================================================================= + + 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 "imstkRigidObject2.h" +#include "imstkLogger.h" +#include "imstkRbdConstraint.h" +#include "imstkRigidBodyModel2.h" +#include "imstkPointSet.h" + +namespace imstk +{ +namespace expiremental +{ +bool +RigidObject2::initialize() +{ + m_rigidBodyModel2 = std::dynamic_pointer_cast<RigidBodyModel2>(m_dynamicalModel); + if (m_rigidBodyModel2 == nullptr) + { + LOG(FATAL) << "Dynamics pointer cast failure in RigidObject2::initialize()"; + return false; + } + + DynamicObject::initialize(); + m_rigidBodyModel2->initialize(); + + updateGeometries(); + m_physicsGeometry->updatePostTransformData(); + + return true; +} + +std::shared_ptr<RigidBodyModel2> +RigidObject2::getRigidBodyModel2() +{ + m_rigidBodyModel2 = std::dynamic_pointer_cast<RigidBodyModel2>(m_dynamicalModel); + return m_rigidBodyModel2; +} + +void +RigidObject2::setDynamicalModel(std::shared_ptr<AbstractDynamicalModel> dynaModel) +{ + m_rigidBodyModel2 = std::dynamic_pointer_cast<RigidBodyModel2>(dynaModel); + m_dynamicalModel = dynaModel; + m_rigidBody = m_rigidBodyModel2->addRigidBody(); +} + +void +RigidObject2::updatePhysicsGeometry() +{ + // Apply the transform back to the geometry + m_physicsGeometry->setTranslation(m_rigidBody->getPosition()); + m_physicsGeometry->setRotation(m_rigidBody->getOrientation()); + m_physicsGeometry->updatePostTransformData(); + + DynamicObject::updatePhysicsGeometry(); +} +} +} // imstk diff --git a/Source/SceneEntities/Objects/imstkRigidObject2.h b/Source/SceneEntities/Objects/imstkRigidObject2.h new file mode 100644 index 0000000000000000000000000000000000000000..1a65255404a033e587fdc74827046cbc1dc70909 --- /dev/null +++ b/Source/SceneEntities/Objects/imstkRigidObject2.h @@ -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. + +=========================================================================*/ + +#pragma once + +#include "imstkDynamicObject.h" + +namespace imstk +{ +class PointSet; +namespace expiremental +{ +class RigidBodyModel2; +struct RigidBody; + +/// +/// \class RigidObject2 +/// +/// \brief Scene objects that are governed by rigid body dynamics +/// +class RigidObject2 : public DynamicObject +{ +public: + explicit RigidObject2(const std::string& name) : DynamicObject(name) + { + m_type = Type::Rigid2; + } + + virtual ~RigidObject2() = default; + +public: + /// + /// \brief Initialize the rigid scene object + /// + bool initialize() override; + + /// + /// \brief Add local force at a position relative to object + /// + //void addForce(const Vec3d& force, const Vec3d& pos, bool wakeup = true); + + std::shared_ptr<RigidBodyModel2> getRigidBodyModel2(); + + /// + /// \brief Returns body in the model + /// + std::shared_ptr<RigidBody> getRigidBody() const { return m_rigidBody; } + + /// + /// \brief Sets the model, and creates the body within the model + /// + void setDynamicalModel(std::shared_ptr<AbstractDynamicalModel> dynaModel) override; + + /// + /// \brief Updates the physics geometry of the object + /// + void updatePhysicsGeometry() override; + +protected: + std::shared_ptr<RigidBodyModel2> m_rigidBodyModel2; + std::shared_ptr<RigidBody> m_rigidBody; ///> Gives the actual body within the model +}; +} +} // imstk \ No newline at end of file diff --git a/Source/SceneEntities/Objects/imstkSPHObject.cpp b/Source/SceneEntities/Objects/imstkSPHObject.cpp index b18f3e5a37136a983624a12b0df2d99298277675..33f8d209ceb32460d9a088582fee12ed2666ab74 100644 --- a/Source/SceneEntities/Objects/imstkSPHObject.cpp +++ b/Source/SceneEntities/Objects/imstkSPHObject.cpp @@ -52,4 +52,11 @@ SPHObject::initialize() return true; } + +std::shared_ptr<SPHModel> +SPHObject::getSPHModel() +{ + m_SPHModel = std::dynamic_pointer_cast<SPHModel>(m_dynamicalModel); + return m_SPHModel; +} } // end namespace imstk diff --git a/Source/SceneEntities/Objects/imstkSPHObject.h b/Source/SceneEntities/Objects/imstkSPHObject.h index e2d150ed5a840f5f782acf904bf7c48035a16565..99d71291f0787dbe80a2dc293dbdfd4d2ef55977 100644 --- a/Source/SceneEntities/Objects/imstkSPHObject.h +++ b/Source/SceneEntities/Objects/imstkSPHObject.h @@ -42,16 +42,16 @@ public: public: /// - /// \brief Initialize the SPH scene object + /// \brief Get the SPH model of the object /// - bool initialize() override; + std::shared_ptr<SPHModel> getSPHModel(); std::shared_ptr<SPHModel> getDynamicalSPHModel(); /// - /// \brief Get the SPH model of the object + /// \brief Initialize the SPH scene object /// - std::shared_ptr<SPHModel> getSPHModel() const { assert(m_SPHModel); return m_SPHModel; } + bool initialize() override; protected: std::shared_ptr<SPHModel> m_SPHModel = nullptr; diff --git a/Source/SceneEntities/Objects/imstkSceneObject.cpp b/Source/SceneEntities/Objects/imstkSceneObject.cpp index 34aaad5cdab3eb2bb8f9127175c61946f598b847..36850d6da68b57a536745445d3797d9c11f180da 100644 --- a/Source/SceneEntities/Objects/imstkSceneObject.cpp +++ b/Source/SceneEntities/Objects/imstkSceneObject.cpp @@ -21,6 +21,7 @@ #include "imstkSceneObject.h" #include "imstkTaskGraph.h" +#include "imstkVisualModel.h" namespace imstk { diff --git a/Source/SceneEntities/Objects/imstkSceneObject.h b/Source/SceneEntities/Objects/imstkSceneObject.h index fd1bb82685b31327a1b5118199daf7d95b336830..46c9c115bf766e7aba856d8df1b88ff604799e90 100644 --- a/Source/SceneEntities/Objects/imstkSceneObject.h +++ b/Source/SceneEntities/Objects/imstkSceneObject.h @@ -21,14 +21,15 @@ #pragma once -#include "imstkVisualModel.h" #include "imstkSceneEntity.h" +#include <memory> #include <string> #include <vector> namespace imstk { +class VisualModel; class DeviceClient; class Geometry; class TaskGraph; @@ -49,11 +50,13 @@ public: Animation, Colliding, Rigid, + Rigid2, FEMDeformable, ReducedFEMDeformable, Pbd, SPH, - Physiology + Physiology, + LevelSetDeformable }; /// @@ -64,7 +67,7 @@ public: /// /// \brief Destructor /// - virtual ~SceneObject() = default; + virtual ~SceneObject() override = default; public: /// diff --git a/Source/SceneEntities/Objects/imstkVisualModel.cpp b/Source/SceneEntities/Objects/imstkVisualModel.cpp index 9ec3c859847206d902339a212c9002ada003887b..68530b3188092b325f13eb9dda3a1415b5ac5c38 100644 --- a/Source/SceneEntities/Objects/imstkVisualModel.cpp +++ b/Source/SceneEntities/Objects/imstkVisualModel.cpp @@ -20,9 +20,7 @@ =========================================================================*/ #include "imstkVisualModel.h" -#include "imstkGeometry.h" #include "imstkRenderMaterial.h" -#include "imstkDebugRenderGeometry.h" namespace imstk { diff --git a/Source/SceneEntities/imstkSceneEntity.h b/Source/SceneEntities/imstkSceneEntity.h index 4ab41d5d82069300f9489eb4dc349993adfe8003..625737f212c6c71082960648362b767437fee8a3 100644 --- a/Source/SceneEntities/imstkSceneEntity.h +++ b/Source/SceneEntities/imstkSceneEntity.h @@ -34,6 +34,8 @@ using EntityID = unsigned long; class SceneEntity { public: + virtual ~SceneEntity() = default; + /// /// \brief Get ID (ALWAYS query the ID in your code, DO NOT hardcode it) /// \returns ID of entity diff --git a/Source/SimulationManager/CMakeLists.txt b/Source/SimulationManager/CMakeLists.txt index 446ecf2392c6ae2c918a6c4337904169e7dbf542..291c0b51dc709ca0fae76181e5d35b8b02756ae5 100644 --- a/Source/SimulationManager/CMakeLists.txt +++ b/Source/SimulationManager/CMakeLists.txt @@ -6,29 +6,33 @@ set(VTK_H_FILES VTKRenderer/imstkVTKTextStatusManager.h VTKRenderer/imstkVTKInteractorStyle.h VTKRenderer/imstkVTKScreenCaptureUtility.h + VTKRenderer/imstkAbstractVTKViewer.h + VTKRenderer/imstkVTKOpenVRViewer.h VTKRenderer/imstkVTKViewer.h - VTKRenderer/imstkOpenVRCommand.h) + VTKRenderer/imstkVTKInteractorStyleVR.h) set(VTK_CPP_FILES VTKRenderer/imstkVTKTextStatusManager.cpp VTKRenderer/imstkVTKInteractorStyle.cpp VTKRenderer/imstkVTKScreenCaptureUtility.cpp + VTKRenderer/imstkAbstractVTKViewer.cpp + VTKRenderer/imstkVTKOpenVRViewer.cpp VTKRenderer/imstkVTKViewer.cpp - VTKRenderer/imstkOpenVRCommand.cpp) + VTKRenderer/imstkVTKInteractorStyleVR.cpp) set(VULKAN_H_FILES VulkanRenderer/imstkVulkanInteractorStyle.h VulkanRenderer/imstkVulkanInteractorStyleFreeCamera.h - VulkanRenderer/imstkVulkanInteractorStyleVR.h VulkanRenderer/imstkVulkanScreenCaptureUtility.h - VulkanRenderer/imstkVulkanViewer.h) + VulkanRenderer/imstkVulkanViewer.h + VulkanRenderer/imstkVulkanInteractorStyleVR.h) set(VULKAN_CPP_FILES VulkanRenderer/imstkVulkanInteractorStyle.cpp VulkanRenderer/imstkVulkanInteractorStyleFreeCamera.cpp - VulkanRenderer/imstkVulkanInteractorStyleVR.cpp VulkanRenderer/imstkVulkanScreenCaptureUtility.cpp - VulkanRenderer/imstkVulkanViewer.cpp) + VulkanRenderer/imstkVulkanViewer.cpp + VulkanRenderer/imstkVulkanInteractorStyleVR.cpp) if( NOT iMSTK_USE_Vulkan ) set(SIMULATIONMANAGER_H_FILES ${VTK_H_FILES}) @@ -43,20 +47,23 @@ else() endif() include(imstkAddLibrary) -imstk_add_library( SimulationManager +imstk_add_library(SimulationManager H_FILES + imstkConsoleThread.h + imstkInteractorStyle.h + imstkKeyboardSceneControl.h + imstkMouseSceneControl.h imstkSceneManager.h - imstkSimulationManager.h - imstkViewer.h imstkScreenCaptureUtility.h - imstkInteractorStyle.h + imstkViewer.h ${SIMULATIONMANAGER_H_FILES} CPP_FILES + imstkConsoleThread.cpp + imstkKeyboardSceneControl.cpp + imstkMouseSceneControl.cpp imstkSceneManager.cpp - imstkSimulationManager.cpp - imstkViewer.cpp imstkScreenCaptureUtility.cpp - imstkInteractorStyle.cpp + imstkViewer.cpp ${SIMULATIONMANAGER_CPP_FILES} SUBDIR_LIST ${SIMULATIONMANAGER_SUBDIR} diff --git a/Source/SimulationManager/VTKRenderer/imstkAbstractVTKViewer.cpp b/Source/SimulationManager/VTKRenderer/imstkAbstractVTKViewer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c516f5f5e3a45efb546b9ee581e83a1b4a2927b7 --- /dev/null +++ b/Source/SimulationManager/VTKRenderer/imstkAbstractVTKViewer.cpp @@ -0,0 +1,168 @@ +/*========================================================================= + + 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 "imstkAbstractVTKViewer.h" +#include "imstkLogger.h" +#include "imstkScene.h" +#include "imstkVTKInteractorStyle.h" +#include "imstkVTKRenderer.h" + +#include <vtkCallbackCommand.h> +#include <vtkRenderer.h> +#include <vtkRenderWindow.h> +#include <vtkRenderWindowInteractor.h> +#include <vtkCallbackCommand.h> + +namespace imstk +{ +AbstractVTKViewer::AbstractVTKViewer(std::string name) : Viewer(name) +{ + viewerDisabledCallback = vtkSmartPointer<vtkCallbackCommand>::New(); + viewerDisabledCallback->SetCallback(viewerDisabled); + viewerDisabledCallback->SetClientData(this); + viewerEnabledCallback = vtkSmartPointer<vtkCallbackCommand>::New(); + viewerEnabledCallback->SetCallback(viewerEnabled); + viewerEnabledCallback->SetClientData(this); +} + +Renderer::Mode +AbstractVTKViewer::getRenderingMode() const +{ + return this->getActiveRenderer()->getMode(); +} + +void +AbstractVTKViewer::stopThread() +{ + // close the rendering window + m_vtkRenderWindow->Finalize(); + + // Terminate the interactor + m_vtkRenderWindow->GetInteractor()->TerminateApp(); +} + +void +AbstractVTKViewer::pause(bool sync) +{ + // It doesn't actually stop until disable event + if (m_status == ThreadStatus::Inactive) + { + return; + } + + this->postEvent(Event(EventType::Pause)); + + pauseThread(); + + if (m_status == ThreadStatus::Running) + { + // Request that it disables + + // If sync, wait until the module actually pauses before returning from function + if (sync) + { + m_vtkRenderWindow->GetInteractor()->AddObserver(vtkCallbackCommand::DisableEvent, viewerDisabledCallback); + m_vtkRenderWindow->GetInteractor()->Disable(); + while (m_status != ThreadStatus::Paused) { } + m_vtkRenderWindow->GetInteractor()->RemoveObserver(viewerDisabledCallback); + } + else + { + m_vtkRenderWindow->GetInteractor()->Disable(); + } + } +} + +void +AbstractVTKViewer::resume(bool sync) +{ + if (m_status == ThreadStatus::Inactive) + { + return; + } + + this->postEvent(Event(EventType::Resume)); + + resumeThread(); + if (m_status == ThreadStatus::Paused) + { + m_requestedStatus = ThreadStatus::Running; + // If sync, wait until the module actually pauses before returning from function + if (sync) + { + m_vtkRenderWindow->GetInteractor()->AddObserver(vtkCallbackCommand::EnableEvent, viewerEnabledCallback); + m_vtkRenderWindow->GetInteractor()->Disable(); + while (m_status != ThreadStatus::Running) { } + m_vtkRenderWindow->GetInteractor()->RemoveObserver(viewerEnabledCallback); + } + else + { + m_vtkRenderWindow->GetInteractor()->Disable(); + } + } +} + +void +AbstractVTKViewer::setSize(const int width, const int height) +{ + if (m_vtkRenderWindow != NULL) + { + m_vtkRenderWindow->SetSize(width, height); + } +} + +void +AbstractVTKViewer::setWindowTitle(const std::string& title) +{ + m_config->m_windowName = title; + if (m_vtkRenderWindow) + { + m_vtkRenderWindow->SetWindowName(title.c_str()); + } +} + +void +AbstractVTKViewer::setBackgroundColors(const Vec3d color1, const Vec3d color2 /*= Vec3d::Zero()*/, const bool gradientBackground /*= false*/) +{ + if (getActiveScene() == nullptr) + { + LOG(WARNING) << "Must set active scene before setting background color"; + return; + } + this->getActiveRenderer()->updateBackground(color1, color2, gradientBackground); +} + +void +AbstractVTKViewer::viewerDisabled(vtkObject* vtkNotUsed(sender), + unsigned long vtkNotUsed(eventId), void* clientData, void* vtkNotUsed(callData)) +{ + imstk::AbstractVTKViewer* viewer = static_cast<imstk::AbstractVTKViewer*>(clientData); + viewer->m_status = ThreadStatus::Paused; +} + +void +AbstractVTKViewer::viewerEnabled(vtkObject* vtkNotUsed(sender), + unsigned long vtkNotUsed(eventId), void* clientData, void* vtkNotUsed(callData)) +{ + imstk::AbstractVTKViewer* viewer = static_cast<imstk::AbstractVTKViewer*>(clientData); + viewer->m_status = ThreadStatus::Running; +} +} diff --git a/Source/SimulationManager/VTKRenderer/imstkAbstractVTKViewer.h b/Source/SimulationManager/VTKRenderer/imstkAbstractVTKViewer.h new file mode 100644 index 0000000000000000000000000000000000000000..869a04ff4915759f9df045b0ca46616d1cb6d1c8 --- /dev/null +++ b/Source/SimulationManager/VTKRenderer/imstkAbstractVTKViewer.h @@ -0,0 +1,116 @@ +/*========================================================================= + + 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 "imstkViewer.h" + +#include <vtkSmartPointer.h> + +class vtkInteractorStyle; +class vtkRenderWindow; +class vtkCallbackCommand; +class vtkObject; + +namespace imstk +{ +class VTKScreenCaptureUtility; +class VTKTextStatusManager; + +/// +/// \class AbstractVTKViewer +/// +/// \brief Subclasses viewer for the VTK rendering back-end +/// \todo: Implement pausing/resuming +/// +class AbstractVTKViewer : public Viewer +{ +protected: + AbstractVTKViewer(std::string name); +public: + virtual ~AbstractVTKViewer() override = default; + +public: + /// + /// \brief Terminate rendering + /// + virtual void stopThread() override; + + /// + /// \brief Pause is reimplemented for VTK viewers + /// + void pause(bool sync = false) override; + + /// + /// \brief Resume is reimplemented for VTK viewers + /// + void resume(bool sync = false) override; + +public: + /// + /// \brief Get the current renderer mode + /// + virtual Renderer::Mode getRenderingMode() const override; + + /// + /// \brief Get pointer to the vtkRenderWindow rendering + /// + vtkSmartPointer<vtkRenderWindow> getVtkRenderWindow() const { return m_vtkRenderWindow; } + + /// + /// \brief Set the render window size + /// + void setSize(const int width, const int height) override; + + /// + /// \brief Set the render window title + /// + void setWindowTitle(const std::string& title) override; + + /// + /// \brief Set the coloring of the screen background + /// If 'gradientBackground' is false or not supplied color1 will fill the entire background + /// + virtual void setBackgroundColors(const Vec3d color1, const Vec3d color2 = Vec3d::Zero(), + const bool gradientBackground = false) override; + + /// + /// \brief Returns the vtk interactor style + /// + std::shared_ptr<vtkInteractorStyle> getVtkInteractorStyle() const { return m_vtkInteractorStyle; } + +protected: + /// + /// \brief Callback for when the viewer is disabled + /// + static void viewerDisabled(vtkObject* sender, unsigned long eventId, void* clientData, void* callData); + /// + /// \brief Callback for when the viewer is enabled + /// + static void viewerEnabled(vtkObject* sender, unsigned long eventId, void* clientData, void* callData); + +protected: + vtkSmartPointer<vtkRenderWindow> m_vtkRenderWindow; + std::shared_ptr<vtkInteractorStyle> m_vtkInteractorStyle; + vtkSmartPointer<vtkCallbackCommand> viewerDisabledCallback; + vtkSmartPointer<vtkCallbackCommand> viewerEnabledCallback; +}; +} // imstk diff --git a/Source/SimulationManager/VTKRenderer/imstkOpenVRCommand.cpp b/Source/SimulationManager/VTKRenderer/imstkOpenVRCommand.cpp deleted file mode 100644 index 2ba7f86c8b2cc2a950e5bf49e5b43eb856b14211..0000000000000000000000000000000000000000 --- a/Source/SimulationManager/VTKRenderer/imstkOpenVRCommand.cpp +++ /dev/null @@ -1,145 +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. - -=========================================================================*/ - -// vtk -#include <vtkObjectFactory.h> - -// imstk -#include "imstkOpenVRCommand.h" -#include "imstkSimulationManager.h" -#include "VTKRenderer/imstkVTKRenderer.h" -#include "imstkCamera.h" - -namespace imstk -{ -void -OpenVRCommand::Execute( - vtkObject* caller, - unsigned long eventId, - void* callData) -{ - /// \todo Clear warnings caller, callData are not used! - // prevent warnings - caller; - callData; - - if (!m_simManager) - { - return; - } - - // trigger button - if (eventId == vtkCommand::CharEvent) - { - SimulationStatus status = m_simManager->getStatus(); - - if (status == SimulationStatus::Running) - { - m_simManager->pause(); - } - - // pause simulation - if (status == SimulationStatus::Inactive) - { - m_simManager->start(); - } - - // continue simulation - if (status == SimulationStatus::Paused) - { - m_simManager->run(); - } - - this->AbortFlagOn(); - } - - if (eventId == vtkCommand::LeftButtonPressEvent) - { - SimulationStatus status = m_simManager->getStatus(); - - // pause simulation - if (status == SimulationStatus::Running) - { - m_simManager->pause(); - } - - // continue simulation - if (status == SimulationStatus::Paused) - { - m_simManager->run(); - } - - this->AbortFlagOn(); - } - - // home button - if (eventId == vtkCommand::FourthButtonReleaseEvent) - { - SimulationStatus status = m_simManager->getStatus(); - - if (status == SimulationStatus::Inactive) - { - m_simManager->start(); - } - else - { - m_simManager->end(); - } - - this->AbortFlagOn(); - } - - // Pad - if (eventId == vtkCommand::RightButtonPressEvent) - { - SimulationStatus status = m_simManager->getStatus(); - // desactivate pad if in simulation mode - if (status != SimulationStatus::Inactive) - { - this->AbortFlagOn(); - } - } - - // grip button - if (eventId == vtkCommand::MiddleButtonPressEvent) - { - /// \todo Take a screenshot - - this->AbortFlagOn(); - } - - // Update render delagates after each rendering - // same as subclassing vtkOpenVRRenderWindowInteractor and - // override DoOneEvent() by calling itself and then updateRenderDelegates() - if (eventId == vtkCommand::StartEvent) - { - //SimulationStatus status = m_simManager->getStatus(); - -#ifndef iMSTK_USE_Vulkan - std::dynamic_pointer_cast<VTKRenderer>(m_simManager->getViewer()->getActiveRenderer())->updateRenderDelegates(); -#endif - } - else - { - //int a = eventId; - } -} -} // imstk diff --git a/Source/SimulationManager/VTKRenderer/imstkVTKInteractorStyle.cpp b/Source/SimulationManager/VTKRenderer/imstkVTKInteractorStyle.cpp index 78a57f8beb24b49ad386afc5ebea67b14c728be7..72f7ec3878e7b52dae34e395e47ba08d8a0738d3 100644 --- a/Source/SimulationManager/VTKRenderer/imstkVTKInteractorStyle.cpp +++ b/Source/SimulationManager/VTKRenderer/imstkVTKInteractorStyle.cpp @@ -19,29 +19,22 @@ =========================================================================*/ -// imstk #include "imstkVTKInteractorStyle.h" -#include "imstkSimulationManager.h" -#include "imstkVTKTextStatusManager.h" -#include "imstkVTKRenderer.h" -#include "imstkCamera.h" -#include "imstkScene.h" +#include "imstkKeyboardDeviceClient.h" +#include "imstkMouseDeviceClient.h" -// vtk -#include "vtkObjectFactory.h" -#include "vtkRenderWindow.h" -#include "vtkRenderWindowInteractor.h" -#include "vtkRenderer.h" -#include "vtkCamera.h" -#include "vtkTextActor.h" +#include <vtkObjectFactory.h> +#include <vtkRenderWindowInteractor.h> +#include <vtkRenderWindow.h> namespace imstk { -VTKInteractorStyle::VTKInteractorStyle() +vtkStandardNewMacro(VTKInteractorStyle); + +VTKInteractorStyle::VTKInteractorStyle() : + m_keyboardDeviceClient(KeyboardDeviceClient::New()), + m_mouseDeviceClient(MouseDeviceClient::New()) { - m_textStatusManager = std::make_shared<VTKTextStatusManager>(this); - m_lastFpsUpdate = std::chrono::high_resolution_clock::now(); - m_lastFps = 60.0; } VTKInteractorStyle::~VTKInteractorStyle() @@ -50,337 +43,82 @@ VTKInteractorStyle::~VTKInteractorStyle() } void -VTKInteractorStyle::SetCurrentRenderer(vtkRenderer* ren) +VTKInteractorStyle::OnTimer() { - // Remove actor if previous renderer - if (this->CurrentRenderer) - { - for (int i = 0; i < VTKTextStatusManager::NumStatusTypes; ++i) - { - this->CurrentRenderer->RemoveActor2D(m_textStatusManager->getTextActor(i)); - } - } - - // Set new current renderer - vtkBaseInteractorStyle::SetCurrentRenderer(ren); - - // Add actor to current renderer - for (int i = 0; i < VTKTextStatusManager::NumStatusTypes; ++i) - { - this->CurrentRenderer->AddActor2D(m_textStatusManager->getTextActor(i)); - } + m_updateFunc(); } void -VTKInteractorStyle::OnTimer() +VTKInteractorStyle::OnKeyPress() { - auto renderer = std::static_pointer_cast<VTKRenderer>(m_simManager->getViewer()->getActiveRenderer()); - - // Update Camera - renderer->updateSceneCamera(m_simManager->getActiveScene()->getCamera()); - - // Update render delegates - renderer->updateRenderDelegates(); - - // Reset camera clipping range - this->CurrentRenderer->ResetCameraClippingRange(); - - if (m_displayFps) - { - // Update framerate value display - auto now = std::chrono::high_resolution_clock::now(); - double visualFPS = 1e6 / static_cast<double>(std::chrono::duration_cast<std::chrono::microseconds>(now - m_pre).count()); - visualFPS = 0.1 * visualFPS + 0.9 * m_lastFps; - m_lastFps = visualFPS; - - int t = static_cast<int>(std::chrono::duration_cast<std::chrono::milliseconds>(now - m_lastFpsUpdate).count()); - if (t > 250) //wait 250ms before updating displayed value - { - double physicalFPS; - if (m_simManager->getStatus() != SimulationStatus::Paused) - { - physicalFPS = m_simManager->getActiveScene()->getFPS(); - } - else - { - physicalFPS = -1.0; // negative value means paused - } - - m_textStatusManager->setFPS(visualFPS, physicalFPS); - m_lastFpsUpdate = now; - } - m_pre = now; - } - - // Render - this->Interactor->Render(); - m_post = std::chrono::high_resolution_clock::now(); - - // Plan next render - this->Interactor->CreateOneShotTimer(0); - - // Call custom behavior - if (m_onTimerFunction) - { - // Call the custom behavior to run on every frame - m_onTimerFunction(this); - } + // Submit the change to the keyboard device client + m_keyboardDeviceClient->emitKeyDown(this->Interactor->GetKeyCode()); } void -VTKInteractorStyle::OnChar() +VTKInteractorStyle::OnKeyRelease() { - char key = this->Interactor->GetKeyCode(); - - // Call custom function if exists, and return - // if it returned `override=true` - if (m_onCharFunctionMap.count(key) - && m_onCharFunctionMap.at(key) - && m_onCharFunctionMap.at(key)(this)) - { - return; - } - - SimulationStatus status = m_simManager->getStatus(); - - if (key == ' ') - { - // pause simulation - if (status == SimulationStatus::Running) - { - m_simManager->pause(); - } - // play simulation - else if (status == SimulationStatus::Paused) - { - m_simManager->run(); - } - // Launch simulation if inactive - if (status == SimulationStatus::Inactive) - { - m_textStatusManager->setStatusVisibility(VTKTextStatusManager::FPS, m_displayFps); - m_simManager->start(SimulationStatus::Running); - } - } - else if (status != SimulationStatus::Inactive - && (key == 'q' || key == 'Q' || key == 'e' || key == 'E')) // end Simulation - { - m_textStatusManager->setStatusVisibility(VTKTextStatusManager::FPS, false); - //m_simManager->endSimulation(); - } - else if (key == 'd' || key == 'D') // switch rendering mode - { - if (m_simManager->getViewer()->getRenderingMode() != Renderer::Mode::Simulation) - { - m_simManager->getViewer()->setRenderingMode(Renderer::Mode::Simulation); - } - else - { - m_simManager->getViewer()->setRenderingMode(Renderer::Mode::Debug); - } - } - else if (key == '\u001B') // quit viewer - { - m_simManager->getViewer()->endRenderingLoop(); - } - else if (key == 'p' || key == 'P') // switch framerate display - { - m_displayFps = !m_displayFps; - m_textStatusManager->setStatusVisibility(VTKTextStatusManager::FPS, m_displayFps); - this->Interactor->Render(); - } - else if (key == 'r' || key == 'R') - { - m_simManager->reset(); - } + // Submit the change to the keyboard device client + m_keyboardDeviceClient->emitKeyUp(this->Interactor->GetKeyCode()); } void VTKInteractorStyle::OnMouseMove() { - // Call custom function if exists, and return - // if it returned `override=true` - if (m_onMouseMoveFunction - && m_onMouseMoveFunction(this)) - { - return; - } - - // Default behavior : ignore mouse if simulation active - if (m_simManager->getViewer()->getRenderingMode() != Renderer::Mode::Debug) - { - return; - } - - // Else : use base class interaction - vtkBaseInteractorStyle::OnMouseMove(); + Vec2i mousePos; + this->Interactor->GetEventPosition(mousePos[0], mousePos[1]); + Vec2i dim; + Interactor->GetSize(dim[0], dim[1]); + m_mouseDeviceClient->updateMousePos(mousePos.cast<double>().cwiseQuotient(dim.cast<double>())); } void VTKInteractorStyle::OnLeftButtonDown() { - // Call custom function if exists, and return - // if it returned `override=true` - if (m_onLeftButtonDownFunction - && m_onLeftButtonDownFunction(this)) - { - return; - } - - // Default behavior : ignore mouse if simulation active - if (m_simManager->getViewer()->getRenderingMode() != Renderer::Mode::Debug) - { - return; - } - - // Else : use base class interaction - vtkBaseInteractorStyle::OnLeftButtonDown(); + m_mouseDeviceClient->emitButtonPress(LEFT_BUTTON); } void VTKInteractorStyle::OnLeftButtonUp() { - // Call custom function if exists, and return - // if it returned `override=true` - if (m_onLeftButtonUpFunction - && m_onLeftButtonUpFunction(this)) - { - return; - } - - // Default behavior : ignore mouse if simulation active - if (m_simManager->getViewer()->getRenderingMode() != Renderer::Mode::Debug) - { - return; - } - - // Else : use base class interaction - vtkBaseInteractorStyle::OnLeftButtonUp(); + m_mouseDeviceClient->emitButtonRelease(LEFT_BUTTON); } void VTKInteractorStyle::OnMiddleButtonDown() { - // Call custom function if exists, and return - // if it returned `override=true` - if (m_onMiddleButtonDownFunction - && m_onMiddleButtonDownFunction(this)) - { - return; - } - - // Default behavior : ignore mouse if simulation active - if (m_simManager->getViewer()->getRenderingMode() != Renderer::Mode::Debug) - { - return; - } - - // Else : use base class interaction - vtkBaseInteractorStyle::OnMiddleButtonDown(); + m_mouseDeviceClient->emitButtonPress(MIDDLE_BUTTON); } void VTKInteractorStyle::OnMiddleButtonUp() { - // Call custom function if exists, and return - // if it returned `override=true` - if (m_onMiddleButtonUpFunction - && m_onMiddleButtonUpFunction(this)) - { - return; - } - - // Default behavior : ignore mouse if simulation active - if (m_simManager->getViewer()->getRenderingMode() != Renderer::Mode::Debug) - { - return; - } - - // Else : use base class interaction - vtkBaseInteractorStyle::OnMiddleButtonUp(); + m_mouseDeviceClient->emitButtonRelease(MIDDLE_BUTTON); } void VTKInteractorStyle::OnRightButtonDown() { - // Call custom function if exists, and return - // if it returned `override=true` - if (m_onRightButtonDownFunction - && m_onRightButtonDownFunction(this)) - { - return; - } - - // Default behavior : ignore mouse if simulation active - if (m_simManager->getViewer()->getRenderingMode() != Renderer::Mode::Debug) - { - return; - } - - // Else : use base class interaction - vtkBaseInteractorStyle::OnRightButtonDown(); + m_mouseDeviceClient->emitButtonPress(RIGHT_BUTTON); } void VTKInteractorStyle::OnRightButtonUp() { - // Call custom function if exists, and return - // if it returned `override=true` - if (m_onRightButtonUpFunction - && m_onRightButtonUpFunction(this)) - { - return; - } - - // Default behavior : ignore mouse if simulation active - if (m_simManager->getViewer()->getRenderingMode() != Renderer::Mode::Debug) - { - return; - } - - // Else : use base class interaction - vtkBaseInteractorStyle::OnRightButtonUp(); + m_mouseDeviceClient->emitButtonRelease(RIGHT_BUTTON); } void VTKInteractorStyle::OnMouseWheelForward() { - // Call custom function if exists, and return - // if it returned `override=true` - if (m_onMouseWheelForwardFunction - && m_onMouseWheelForwardFunction(this)) - { - return; - } - - // Default behavior : ignore mouse if simulation active - if (m_simManager->getViewer()->getRenderingMode() != Renderer::Mode::Debug) - { - return; - } - - // Else : use base class interaction - vtkBaseInteractorStyle::OnMouseWheelForward(); + // \todo: VTK provides no scroll amount? + m_mouseDeviceClient->emitScroll(-0.2); } void VTKInteractorStyle::OnMouseWheelBackward() { - // Call custom function if exists, and return - // if it returned `override=true` - if (m_onMouseWheelBackwardFunction - && m_onMouseWheelBackwardFunction(this)) - { - return; - } - - // Default behavior : ignore mouse if simulation active - if (m_simManager->getViewer()->getRenderingMode() != Renderer::Mode::Debug) - { - return; - } - - // Else : use base class interaction - vtkBaseInteractorStyle::OnMouseWheelBackward(); + // \todo: VTK provides no scroll amount? + m_mouseDeviceClient->emitScroll(0.2); +} } -} // imstk diff --git a/Source/SimulationManager/VTKRenderer/imstkVTKInteractorStyle.h b/Source/SimulationManager/VTKRenderer/imstkVTKInteractorStyle.h index 69a9c3d3bebc06a5d21deca5bc38eb70f6e1756e..45a4b45659100254fb27946f1d6059980dbdcd44 100644 --- a/Source/SimulationManager/VTKRenderer/imstkVTKInteractorStyle.h +++ b/Source/SimulationManager/VTKRenderer/imstkVTKInteractorStyle.h @@ -21,36 +21,28 @@ #pragma once -#include <chrono> -#include <memory> - #include "imstkInteractorStyle.h" -#include "vtkInteractorStyleTrackballCamera.h" +#include <vtkInteractorStyleTrackballCamera.h> namespace imstk { -class SimulationManager; -class VTKTextStatusManager; -/// Base class of the vtk interactor style used -using vtkBaseInteractorStyle = vtkInteractorStyleTrackballCamera; +class KeyboardDeviceClient; +class MouseDeviceClient; /// /// \class VTKInteractorStyle /// -/// \brief TODO +/// \brief Interactor styles forward their controls to imstk objects /// -class VTKInteractorStyle : public vtkBaseInteractorStyle, public InteractorStyle +class VTKInteractorStyle : public vtkInteractorStyleTrackballCamera, public InteractorStyle { public: - vtkTypeMacro(VTKInteractorStyle, vtkBaseInteractorStyle) VTKInteractorStyle(); + static VTKInteractorStyle* New(); + vtkTypeMacro(VTKInteractorStyle, vtkInteractorStyleTrackballCamera) VTKInteractorStyle(); virtual ~VTKInteractorStyle() override; - /// - /// \brief Set current renderer - /// - virtual void SetCurrentRenderer(vtkRenderer* ren) override; - +public: /// /// \brief Slot for timer tick /// @@ -59,7 +51,19 @@ public: /// /// \brief Slot for key pressed /// - virtual void OnChar() override; + virtual void OnKeyPress() override; + + /// + /// \brief Slot for key released + /// + virtual void OnKeyRelease() override; + + /// + /// \brief Filter out these events + /// + virtual void OnKeyDown() override { } + virtual void OnKeyUp() override { } + virtual void OnChar() override { } /// /// \brief Slot for moved mouse cursor @@ -114,27 +118,11 @@ public: virtual void OnFourthButtonUp() override {} virtual void OnFifthButtonUp() override {} - /// - /// \brief Return the pointer to simulation manager - /// - SimulationManager* getSimulationManager() { return m_simManager; } - - /// - /// \brief Return the window status handler - /// - const std::shared_ptr<VTKTextStatusManager>& getTextStatusManager() { return m_textStatusManager; } + std::shared_ptr<KeyboardDeviceClient> getKeyboardDeviceClient() const { return m_keyboardDeviceClient; } + std::shared_ptr<MouseDeviceClient> getMouseDeviceClient() const { return m_mouseDeviceClient; } private: - - friend class VTKViewer; - - SimulationManager* m_simManager; ///> SimulationManager owning the current simulation being interacted with - std::chrono::high_resolution_clock::time_point m_pre; ///> time point pre-rendering - std::chrono::high_resolution_clock::time_point m_post; ///> time point post-rendering - std::chrono::high_resolution_clock::time_point m_lastFpsUpdate; ///> time point for last framerate display update - - std::shared_ptr<VTKTextStatusManager> m_textStatusManager; ///> Handle text statuses, including fps status and custom text status - bool m_displayFps = false; ///> hide or display framerate - double m_lastFps; ///> last framerate value used for moving average estimate + std::shared_ptr<KeyboardDeviceClient> m_keyboardDeviceClient; + std::shared_ptr<MouseDeviceClient> m_mouseDeviceClient; }; } // imstk diff --git a/Source/SimulationManager/VTKRenderer/imstkVTKInteractorStyleVR.cpp b/Source/SimulationManager/VTKRenderer/imstkVTKInteractorStyleVR.cpp new file mode 100644 index 0000000000000000000000000000000000000000..47c9723cfd052a597b1efda9aa28686393791032 --- /dev/null +++ b/Source/SimulationManager/VTKRenderer/imstkVTKInteractorStyleVR.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 "imstkVTKInteractorStyleVR.h" +#include "imstkOpenVRDeviceClient.h" + +#include <vtkObjectFactory.h> +#include <vtkOpenVRRenderWindowInteractor.h> + +vtkStandardNewMacro(vtkInteractorStyleVR); + +vtkInteractorStyleVR::vtkInteractorStyleVR() +{ + // Setup the VR device clients + m_leftControllerDeviceClient = imstk::OpenVRDeviceClient::New(OPENVR_LEFT_CONTROLLER); + m_rightControllerDeviceClient = imstk::OpenVRDeviceClient::New(OPENVR_RIGHT_CONTROLLER); + m_hmdDeviceClient = imstk::OpenVRDeviceClient::New(OPENVR_HMD); +} + +void +vtkInteractorStyleVR::OnMove3D(vtkEventData* eventData) +{ + if (eventData->GetType() != vtkCommand::Move3DEvent) + { + return; + } + vtkEventDataDevice3D* eventDataDevice = static_cast<vtkEventDataDevice3D*>(eventData); + if (vtkEventDataDevice::LeftController == eventDataDevice->GetDevice()) + { + imstk::Vec3d pos; + eventDataDevice->GetWorldPosition(pos.data()); + double orientation[4]; + eventDataDevice->GetWorldOrientation(orientation); + m_leftControllerDeviceClient->setPose(pos, imstk::Quatd(imstk::Rotd(vtkMath::RadiansFromDegrees(orientation[0]), + imstk::Vec3d(orientation[1], orientation[2], orientation[3])))); + } + else if (vtkEventDataDevice::RightController == eventDataDevice->GetDevice()) + { + imstk::Vec3d pos; + eventDataDevice->GetWorldPosition(pos.data()); + double orientation[4]; + eventDataDevice->GetWorldOrientation(orientation); + m_rightControllerDeviceClient->setPose(pos, imstk::Quatd(imstk::Rotd(vtkMath::RadiansFromDegrees(orientation[0]), + imstk::Vec3d(orientation[1], orientation[2], orientation[3])))); + } + else if (vtkEventDataDevice::HeadMountedDisplay == eventDataDevice->GetDevice()) + { + imstk::Vec3d pos; + eventDataDevice->GetWorldPosition(pos.data()); + double orientation[4]; + eventDataDevice->GetWorldOrientation(orientation); + m_hmdDeviceClient->setPose(pos, imstk::Quatd(imstk::Rotd(vtkMath::RadiansFromDegrees(orientation[0]), + imstk::Vec3d(orientation[1], orientation[2], orientation[3])))); + } +} + +void +vtkInteractorStyleVR::OnButton3D(vtkEventData* eventData) +{ + if (eventData->GetType() != vtkCommand::Button3DEvent) + { + return; + } + vtkEventDataButton3D* eventDataButton = static_cast<vtkEventDataButton3D*>(eventData); + const vtkEventDataDevice device = eventDataButton->GetDevice(); + const vtkEventDataAction action = eventDataButton->GetAction(); + const vtkEventDataDeviceInput input = eventDataButton->GetInput(); + + switch (action) + { + case vtkEventDataAction::Press: + if (device == vtkEventDataDevice::LeftController) + { + m_leftControllerDeviceClient->emitButtonPress(static_cast<int>(input)); + } + else if (device == vtkEventDataDevice::RightController) + { + m_rightControllerDeviceClient->emitButtonPress(static_cast<int>(input)); + } + break; + case vtkEventDataAction::Release: + if (device == vtkEventDataDevice::LeftController) + { + m_leftControllerDeviceClient->emitButtonRelease(static_cast<int>(input)); + } + else if (device == vtkEventDataDevice::RightController) + { + m_rightControllerDeviceClient->emitButtonRelease(static_cast<int>(input)); + } + break; + case vtkEventDataAction::Touch: + if (device == vtkEventDataDevice::LeftController) + { + m_leftControllerDeviceClient->emitButtonTouched(static_cast<int>(input)); + } + else if (device == vtkEventDataDevice::RightController) + { + m_rightControllerDeviceClient->emitButtonTouched(static_cast<int>(input)); + } + break; + case vtkEventDataAction::Untouch: + if (device == vtkEventDataDevice::LeftController) + { + m_leftControllerDeviceClient->emitButtonUntouched(static_cast<int>(input)); + } + else if (device == vtkEventDataDevice::RightController) + { + m_rightControllerDeviceClient->emitButtonUntouched(static_cast<int>(input)); + } + break; + default: + break; + } + ; +} \ No newline at end of file diff --git a/Source/SimulationManager/VTKRenderer/imstkVTKInteractorStyleVR.h b/Source/SimulationManager/VTKRenderer/imstkVTKInteractorStyleVR.h new file mode 100644 index 0000000000000000000000000000000000000000..0e6451469a2ebb562aab25c3eb8578cfd6e00a81 --- /dev/null +++ b/Source/SimulationManager/VTKRenderer/imstkVTKInteractorStyleVR.h @@ -0,0 +1,61 @@ +/*========================================================================= + + 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 "imstkInteractorStyle.h" + +#include <vtkInteractorStyle3D.h> + +namespace imstk +{ +class OpenVRDeviceClient; +} + +/// +/// \brief VTK Interactor style for VR +/// +class vtkInteractorStyleVR : public vtkInteractorStyle3D, public imstk::InteractorStyle +{ +public: + static vtkInteractorStyleVR* New(); + vtkTypeMacro(vtkInteractorStyleVR, vtkInteractorStyle3D); + + void OnMove3D(vtkEventData* edata) override; + void OnButton3D(vtkEventData* edata) override; + void OnTimer() override + { + if (m_updateFunc != nullptr) + { + m_updateFunc(); + } + } + + std::shared_ptr<imstk::OpenVRDeviceClient> getLeftControllerDeviceClient() const { return m_leftControllerDeviceClient; } + std::shared_ptr<imstk::OpenVRDeviceClient> getRightControllerDeviceClient() const { return m_rightControllerDeviceClient; } + std::shared_ptr<imstk::OpenVRDeviceClient> getHmdDeviceClient() const { return m_hmdDeviceClient; } + +public: + vtkInteractorStyleVR(); + +public: + std::shared_ptr<imstk::OpenVRDeviceClient> m_leftControllerDeviceClient; + std::shared_ptr<imstk::OpenVRDeviceClient> m_rightControllerDeviceClient; + std::shared_ptr<imstk::OpenVRDeviceClient> m_hmdDeviceClient; +}; \ No newline at end of file diff --git a/Source/SimulationManager/VTKRenderer/imstkVTKOpenVRViewer.cpp b/Source/SimulationManager/VTKRenderer/imstkVTKOpenVRViewer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cb3d964c2e90ea043db5abaec0cb2db840f70eb2 --- /dev/null +++ b/Source/SimulationManager/VTKRenderer/imstkVTKOpenVRViewer.cpp @@ -0,0 +1,208 @@ +/*========================================================================= + + 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 "imstkVTKOpenVRViewer.h" +#include "imstkDeviceControl.h" +#include "imstkLogger.h" +#include "imstkOpenVRDeviceClient.h" +#include "imstkScene.h" +#include "imstkVTKInteractorStyle.h" +#include "imstkVTKInteractorStyleVR.h" +#include "imstkVTKRenderer.h" + +#include <vtkOpenVRRenderer.h> +#include <vtkOpenVRRenderWindow.h> +#include <vtkOpenVRRenderWindowInteractor.h> +#include <vtkOpenVRModel.h> + +namespace imstk +{ +VTKOpenVRViewer::VTKOpenVRViewer(std::string name) : AbstractVTKViewer(name) +{ + // Create the interactor style + auto vrInteractorStyle = std::make_shared<vtkInteractorStyleVR>(); + m_interactorStyle = std::dynamic_pointer_cast<InteractorStyle>(vrInteractorStyle); + m_vtkInteractorStyle = std::dynamic_pointer_cast<vtkInteractorStyle>(m_interactorStyle); + m_interactorStyle->setUpdateFunc([&]() { updateThread(); }); + + // Create the interactor + vtkNew<vtkOpenVRRenderWindowInteractor> iren; + iren->SetInteractorStyle(m_vtkInteractorStyle.get()); + + // Create the RenderWindow + m_vtkRenderWindow = vtkSmartPointer<vtkOpenVRRenderWindow>::New(); + m_vtkRenderWindow->SetInteractor(iren); + iren->SetRenderWindow(m_vtkRenderWindow); + m_vtkRenderWindow->HideCursor(); + + m_vrDeviceClients.push_back(vrInteractorStyle->getLeftControllerDeviceClient()); + m_vrDeviceClients.push_back(vrInteractorStyle->getRightControllerDeviceClient()); + m_vrDeviceClients.push_back(vrInteractorStyle->getHmdDeviceClient()); +} + +void +VTKOpenVRViewer::setActiveScene(const std::shared_ptr<Scene>& scene) +{ + // If already current scene + if (scene == m_activeScene) + { + LOG(WARNING) << scene->getName() << " already is the viewer current scene."; + return; + } + + // If the current scene has a renderer, remove it + if (m_activeScene) + { + auto vtkRenderer = std::dynamic_pointer_cast<VTKRenderer>(this->getActiveRenderer())->getVtkRenderer(); + if (m_vtkRenderWindow->HasRenderer(vtkRenderer)) + { + m_vtkRenderWindow->RemoveRenderer(vtkRenderer); + } + } + + // Update current scene + m_activeScene = scene; + + // Create renderer if it doesn't exist + if (!m_rendererMap.count(m_activeScene)) + { + m_rendererMap[m_activeScene] = std::make_shared<VTKRenderer>(m_activeScene, true); + } + + // Cast to VTK renderer + auto vtkRenderer = std::dynamic_pointer_cast<VTKRenderer>(this->getActiveRenderer())->getVtkRenderer(); + + // Set renderer to renderWindow + m_vtkRenderWindow->AddRenderer(vtkRenderer); + + m_vtkInteractorStyle->SetCurrentRenderer(vtkRenderer); +} + +void +VTKOpenVRViewer::setRenderingMode(const Renderer::Mode mode) +{ + if (!m_activeScene) + { + LOG(WARNING) << "Missing scene, can not set rendering mode.\n" + << "Use Viewer::setCurrentScene to setup scene."; + return; + } + + // Setup renderer + this->getActiveRenderer()->setMode(mode, true); + if (m_status != ThreadStatus::Running) + { + return; + } + + // Render to update displayed actors + m_vtkRenderWindow->Render(); +} + +void +VTKOpenVRViewer::startThread() +{ + // Print all controls on viewer + for (auto control : m_controls) + { + control->printControls(); + } + + // VR interactor doesn't support timers, here we throw timer event every update + // another option would be to conform VTKs VR interactor + vtkSmartPointer<vtkOpenVRRenderWindowInteractor> iren = vtkOpenVRRenderWindowInteractor::SafeDownCast(m_vtkRenderWindow->GetInteractor()); + //iren->Start(); // Cannot use + if (iren->HasObserver(vtkCommand::StartEvent)) + { + iren->InvokeEvent(vtkCommand::StartEvent, nullptr); + return; + } + iren->Initialize(); + + // Hide the device overlays + // \todo: put in debug mode + vtkSmartPointer<vtkOpenVRRenderWindow> renWin = vtkOpenVRRenderWindow::SafeDownCast(m_vtkRenderWindow); + renWin->Initialize(); + renWin->Render(); // Must do one render to initialize vtkOpenVRModel's to then hide the controllers + + //renWin->GetTrackedDeviceModel(vr::trackeddevice) + // Hide all controllers + for (int i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) + { + vtkOpenVRModel* trackedDeviceModel = renWin->GetTrackedDeviceModel(i); + if (trackedDeviceModel != nullptr) + { + trackedDeviceModel->SetVisibility(false); + } + } + + while (!iren->GetDone()) + { + auto vtkRen = std::dynamic_pointer_cast<VTKRenderer>(getActiveRenderer()); + iren->DoOneEvent(vtkOpenVRRenderWindow::SafeDownCast(m_vtkRenderWindow), vtkOpenVRRenderer::SafeDownCast(vtkRen->getVtkRenderer())); + iren->InvokeEvent(vtkCommand::TimerEvent); + } +} + +std::shared_ptr<OpenVRDeviceClient> +VTKOpenVRViewer::getVRDeviceClient(int deviceType) +{ + auto iter = std::find_if(m_vrDeviceClients.begin(), m_vrDeviceClients.end(), + [&](const std::shared_ptr<OpenVRDeviceClient>& deviceClient) + { + return static_cast<int>(deviceClient->getDeviceType()) == deviceType; + }); + return (iter == m_vrDeviceClients.end()) ? nullptr : *iter; +} + +void +VTKOpenVRViewer::updateThread() +{ + this->postEvent(Event(EventType::PreUpdate)); + + // Update all controls + for (auto control : m_controls) + { + control->update(); + } + + std::shared_ptr<imstk::VTKRenderer> renderer = std::dynamic_pointer_cast<imstk::VTKRenderer>(getActiveRenderer()); + if (renderer == nullptr) + { + return; + } + + // Update Camera + // \todo: No programmatic control over VR camera currently + //renderer->updateSceneCamera(getActiveScene()->getCamera()); + + // Update render delegates + renderer->updateRenderDelegates(); + + // Render + m_vtkRenderWindow->GetInteractor()->Render(); + + this->postEvent(Event(EventType::PostUpdate)); + + // Plan next render + m_vtkRenderWindow->GetInteractor()->CreateOneShotTimer(0); +} +} diff --git a/Source/SimulationManager/VTKRenderer/imstkVTKOpenVRViewer.h b/Source/SimulationManager/VTKRenderer/imstkVTKOpenVRViewer.h new file mode 100644 index 0000000000000000000000000000000000000000..2d57e5940cf11f8d9e2223b54415affe981111e7 --- /dev/null +++ b/Source/SimulationManager/VTKRenderer/imstkVTKOpenVRViewer.h @@ -0,0 +1,87 @@ +/*========================================================================= + + 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 "imstkAbstractVTKViewer.h" + +#include <vtkSmartPointer.h> +#include <list> + +class vtkInteractorStyle; +class vtkInteractorStyleVR; +class vtkRenderWindow; + +namespace imstk +{ +class OpenVRDeviceClient; + +/// +/// \class VTKViewer +/// +/// \brief Subclasses viewer for the VTK rendering back-end +/// Creates vtk renderer for each scene. Forwards mouse and keyboard events +/// to the vtk renderwindow +/// +class VTKOpenVRViewer : public AbstractVTKViewer +{ +public: + VTKOpenVRViewer(std::string name = "VTKOpenVRViewer"); + ~VTKOpenVRViewer() override = default; + +public: + /// + /// \brief Start rendering + /// + void startThread() override; + +public: + /// + /// \brief Destructor + /// + void setRenderingMode(const Renderer::Mode mode) override; + + /// + /// \brief Set scene to be rendered + /// + void setActiveScene(const std::shared_ptr<Scene>& scene) override; + + /// + /// \brief Get one of the device clients for VR + /// + std::shared_ptr<OpenVRDeviceClient> getVRDeviceClient(int deviceType); + + /// + /// \brief Acquire the full list of VR devices tied to this viewer + /// + const std::list<std::shared_ptr<OpenVRDeviceClient>>& getVRDeviceClients() const { return m_vrDeviceClients; } + +protected: + void updateThread() override; + +protected: + vtkSmartPointer<vtkRenderWindow> m_vtkRenderWindow; + std::shared_ptr<vtkInteractorStyle> m_vtkInteractorStyle; + + ///> The VR controllers are tied to the view + std::list<std::shared_ptr<OpenVRDeviceClient>> m_vrDeviceClients; +}; +} // imstk diff --git a/Source/SimulationManager/VTKRenderer/imstkVTKScreenCaptureUtility.cpp b/Source/SimulationManager/VTKRenderer/imstkVTKScreenCaptureUtility.cpp index cac4039bb4620b8df9a85bb61f02f9486e9f5e2f..92bd728426130172f849d00ab1aa6dc6d92c3d19 100644 --- a/Source/SimulationManager/VTKRenderer/imstkVTKScreenCaptureUtility.cpp +++ b/Source/SimulationManager/VTKRenderer/imstkVTKScreenCaptureUtility.cpp @@ -22,9 +22,15 @@ #include "imstkVTKScreenCaptureUtility.h" #include "imstkLogger.h" +#include <vtkPNGWriter.h> +#include <vtkRenderWindow.h> +#include <vtkWindowToImageFilter.h> + namespace imstk { -VTKScreenCaptureUtility::VTKScreenCaptureUtility(vtkRenderWindow* const rw, const std::string prefix /*= "Screenshot-"*/) +VTKScreenCaptureUtility::VTKScreenCaptureUtility(vtkRenderWindow* const rw, const std::string prefix /*= "Screenshot-"*/) : + m_windowToImageFilter(vtkSmartPointer<vtkWindowToImageFilter>::New()), + m_pngWriter(vtkSmartPointer<vtkPNGWriter>::New()) { m_screenShotNumber = 0; m_screenShotPrefix = prefix; @@ -66,26 +72,4 @@ VTKScreenCaptureUtility::saveScreenShot() m_screenShotNumber++; } - -unsigned int -VTKScreenCaptureUtility::getScreenShotNumber() const -{ - return m_screenShotNumber; -} - -void -VTKScreenCaptureUtility::setScreenShotPrefix(const std::string newPrefix) -{ - if (m_screenShotPrefix.compare(newPrefix) != 0) - { - m_screenShotPrefix = newPrefix; - m_screenShotNumber = 0; - } -} - -void -VTKScreenCaptureUtility::resetScreenShotNumber() -{ - m_screenShotNumber = 0; -} } // imstk diff --git a/Source/SimulationManager/VTKRenderer/imstkVTKScreenCaptureUtility.h b/Source/SimulationManager/VTKRenderer/imstkVTKScreenCaptureUtility.h index c10b5b23d311e176fe0e29aa74cd9a2e5de6d579..d1be6ad193ef5cb4d563ddb72cf3699da7769a7b 100644 --- a/Source/SimulationManager/VTKRenderer/imstkVTKScreenCaptureUtility.h +++ b/Source/SimulationManager/VTKRenderer/imstkVTKScreenCaptureUtility.h @@ -23,12 +23,11 @@ #include "imstkScreenCaptureUtility.h" -#include <vtkRenderWindow.h> -#include <vtkWindowToImageFilter.h> -#include <vtkPNGWriter.h> -#include <vtkNew.h> +#include <vtkSmartPointer.h> -#include <string> +class vtkPNGWriter; +class vtkRenderWindow; +class vtkWindowToImageFilter; namespace imstk { @@ -48,31 +47,16 @@ public: /// /// \brief Destructor /// - ~VTKScreenCaptureUtility() = default; + virtual ~VTKScreenCaptureUtility() override = default; /// /// \brief Saves the screenshot as a png file /// - virtual void saveScreenShot(); - - /// - /// \brief Get screen shot number - /// - unsigned int getScreenShotNumber() const; - - /// - /// \brief Set screen shot prefix - /// - void setScreenShotPrefix(const std::string newPrefix); - - /// - /// \brief Reset screen shot number to zero - /// - void resetScreenShotNumber(); + virtual void saveScreenShot() override; protected: - vtkNew<vtkWindowToImageFilter> m_windowToImageFilter; - vtkNew<vtkPNGWriter> m_pngWriter; //> using vtk's png writer to save the screenshots - vtkRenderWindow* m_renderWindow; //> render window whose screen shot will be taken + vtkSmartPointer<vtkWindowToImageFilter> m_windowToImageFilter; + vtkSmartPointer<vtkPNGWriter> m_pngWriter; //> using vtk's png writer to save the screenshots + vtkRenderWindow* m_renderWindow; //> render window whose screen shot will be taken }; } // imstk diff --git a/Source/SimulationManager/VTKRenderer/imstkVTKTextStatusManager.cpp b/Source/SimulationManager/VTKRenderer/imstkVTKTextStatusManager.cpp index 102cda91fc654ef868e3504f74ad45319ce0d594..2fb4bd2c5d7ea6f6d2a2873fcfa84c6970c7292b 100644 --- a/Source/SimulationManager/VTKRenderer/imstkVTKTextStatusManager.cpp +++ b/Source/SimulationManager/VTKRenderer/imstkVTKTextStatusManager.cpp @@ -19,27 +19,20 @@ =========================================================================*/ -#include "imstkSimulationManager.h" #include "imstkVTKTextStatusManager.h" #include "imstkVTKInteractorStyle.h" +#include "imstkVTKViewer.h" #include "imstkLogger.h" -#include "imstkCamera.h" -#include "vtkTextActor.h" -#include "vtkRenderWindow.h" -#include "vtkTextProperty.h" - -#include <algorithm> -#include <sstream> -#include <iostream> +#include <vtkRenderWindow.h> +#include <vtkTextActor.h> +#include <vtkTextProperty.h> namespace imstk { -VTKTextStatusManager::VTKTextStatusManager(VTKInteractorStyle* const vtkInteractorStyle) : - m_vtkInteractorStyle(vtkInteractorStyle) +VTKTextStatusManager::VTKTextStatusManager() { - LOG_IF(FATAL, (!vtkInteractorStyle)) << "Invalid vtkInteractorStyle"; - for (int i = 0; i < StatusType::NumStatusTypes; ++i) + for (int i = 0; i < static_cast<int>(StatusType::NumStatusTypes); ++i) { m_StatusActors[i] = vtkTextActor::New(); m_StatusActors[i]->SetVisibility(false); @@ -50,7 +43,7 @@ VTKTextStatusManager::VTKTextStatusManager(VTKInteractorStyle* const vtkInteract VTKTextStatusManager::~VTKTextStatusManager() { - for (int i = 0; i < StatusType::NumStatusTypes; ++i) + for (int i = 0; i < static_cast<int>(StatusType::NumStatusTypes); ++i) { m_StatusActors[i]->Delete(); } @@ -59,7 +52,7 @@ VTKTextStatusManager::~VTKTextStatusManager() vtkTextActor* VTKTextStatusManager::getTextActor(const int i) { - if (i < 0 || i >= StatusType::NumStatusTypes) + if (i < 0 || i >= static_cast<int>(StatusType::NumStatusTypes)) { LOG(WARNING) << "Invalid text actor index"; return m_StatusActors[0]; @@ -70,26 +63,32 @@ VTKTextStatusManager::getTextActor(const int i) void VTKTextStatusManager::setStatusVisibility(const StatusType type, const bool bVisible) { - m_StatusActors[type]->SetVisibility(bVisible); + m_StatusActors[static_cast<int>(type)]->SetVisibility(bVisible); +} + +bool +VTKTextStatusManager::getStatusVisibility(const StatusType type) +{ + return m_StatusActors[static_cast<int>(type)]->GetVisibility(); } void VTKTextStatusManager::setStatusFontSize(const StatusType type, const int fontSize) { - m_StatusFontSizes[type] = fontSize; // Store font size to compute and adjust text location later - m_StatusActors[type]->GetTextProperty()->SetFontSize(fontSize); + m_StatusFontSizes[static_cast<int>(type)] = fontSize; // Store font size to compute and adjust text location later + m_StatusActors[static_cast<int>(type)]->GetTextProperty()->SetFontSize(fontSize); } void VTKTextStatusManager::setStatusFontColor(const StatusType type, const Color color) { - m_StatusActors[type]->GetTextProperty()->SetColor(color.r, color.g, color.b); + m_StatusActors[static_cast<int>(type)]->GetTextProperty()->SetColor(color.r, color.g, color.b); } void VTKTextStatusManager::setStatusDisplayCorner(const StatusType type, const DisplayCorner corner) { - m_StatusDisplayCorners[type] = corner; + m_StatusDisplayCorners[static_cast<int>(type)] = corner; } void @@ -115,39 +114,35 @@ VTKTextStatusManager::setFPS(const double visualFPS, const double physicsFPS) } std::string fpsString = fpsVisualStr + std::string(" | ") + fpsPhysicalStr; - auto fpsStatusCoordinate = computeStatusLocation(m_StatusDisplayCorners[StatusType::FPS], - m_StatusFontSizes[StatusType::FPS], + auto fpsStatusCoordinate = computeStatusLocation(m_StatusDisplayCorners[static_cast<int>(StatusType::FPS)], + m_StatusFontSizes[static_cast<int>(StatusType::FPS)], fpsString); - m_StatusActors[StatusType::FPS]->SetDisplayPosition(fpsStatusCoordinate[0], fpsStatusCoordinate[1]); - m_StatusActors[StatusType::FPS]->SetInput((fpsString).c_str()); + m_StatusActors[static_cast<int>(StatusType::FPS)]->SetDisplayPosition(fpsStatusCoordinate[0], fpsStatusCoordinate[1]); + m_StatusActors[static_cast<int>(StatusType::FPS)]->SetInput((fpsString).c_str()); } void VTKTextStatusManager::setCustomStatus(const std::string& status) { - auto customStatusCoordinate = computeStatusLocation(m_StatusDisplayCorners[StatusType::Custom], - m_StatusFontSizes[StatusType::Custom], + auto customStatusCoordinate = computeStatusLocation(m_StatusDisplayCorners[static_cast<int>(StatusType::Custom)], + m_StatusFontSizes[static_cast<int>(StatusType::Custom)], status); - m_StatusActors[StatusType::Custom]->SetInput(status.c_str()); - m_StatusActors[StatusType::Custom]->SetDisplayPosition(customStatusCoordinate[0], customStatusCoordinate[1]); - m_StatusActors[StatusType::Custom]->SetVisibility(true); + m_StatusActors[static_cast<int>(StatusType::Custom)]->SetInput(status.c_str()); + m_StatusActors[static_cast<int>(StatusType::Custom)]->SetDisplayPosition(customStatusCoordinate[0], customStatusCoordinate[1]); + m_StatusActors[static_cast<int>(StatusType::Custom)]->SetVisibility(true); } void VTKTextStatusManager::clearCustomStatus() { - m_StatusActors[StatusType::Custom]->SetInput(""); - m_StatusActors[StatusType::Custom]->SetVisibility(false); + m_StatusActors[static_cast<int>(StatusType::Custom)]->SetInput(""); + m_StatusActors[static_cast<int>(StatusType::Custom)]->SetVisibility(false); } std::array<int, 2> VTKTextStatusManager::computeStatusLocation(const DisplayCorner corner, const int fontSize, const std::string& text) { - auto simManager = m_vtkInteractorStyle->getSimulationManager(); - LOG_IF(FATAL, (!simManager)) << "Invalid simulation manager"; - - auto viewer = std::dynamic_pointer_cast<VTKViewer>(simManager->getViewer()); - const int* windowSize = viewer->getVtkRenderWindow()->GetSize(); + const int* windowSize = m_viewer->getVtkRenderWindow()->GetSize(); const auto wWidth = windowSize[0]; const auto wHeight = windowSize[1]; const int numLines = static_cast<int>(std::count(text.begin(), text.end(), '\n')) + 1; diff --git a/Source/SimulationManager/VTKRenderer/imstkVTKTextStatusManager.h b/Source/SimulationManager/VTKRenderer/imstkVTKTextStatusManager.h index 1ffcf8aa58a7284d0016eed0b65dcf7e3da80cd9..bcc492e99db29683deb7c48a6bd14243f452823c 100644 --- a/Source/SimulationManager/VTKRenderer/imstkVTKTextStatusManager.h +++ b/Source/SimulationManager/VTKRenderer/imstkVTKTextStatusManager.h @@ -21,9 +21,10 @@ #pragma once -#include <array> - #include "imstkColor.h" +#include "imstkMath.h" + +#include <array> class vtkTextActor; @@ -36,7 +37,8 @@ class vtkTextActor; namespace imstk { -class VTKInteractorStyle; +class VTKViewer; + /// /// \brief The VTKTextStatusManager class /// @@ -46,7 +48,7 @@ public: /// /// \brief The StatusType enum /// - enum StatusType + enum class StatusType { FPS = 0, Custom, @@ -56,7 +58,7 @@ public: /// /// \brief The TextLocation enum /// - enum DisplayCorner + enum class DisplayCorner { LowerLeft, UpperLeft, @@ -64,9 +66,11 @@ public: LowerRight }; - explicit VTKTextStatusManager(VTKInteractorStyle* const vtkInteractorStyle); +public: + explicit VTKTextStatusManager(); virtual ~VTKTextStatusManager(); +public: /// /// \brief Return the text actor at index i /// @@ -77,6 +81,11 @@ public: /// void setStatusVisibility(const StatusType type, const bool bVisible); + /// + /// \brief Get the visibility of the text status + /// + bool getStatusVisibility(const StatusType type); + /// /// \brief Set the font size for the status /// @@ -99,6 +108,11 @@ public: /// void setFPS(const double visualFPS, const double physicsFPS); + /// + /// \brief Set the window size + /// + void setWindowSize(VTKViewer* viewer) { m_viewer = viewer; } + /// /// \brief Set custom status text /// The string parameter should be passed by value, not const reference @@ -116,10 +130,10 @@ private: /// std::array<int, 2> computeStatusLocation(const DisplayCorner corner, const int fontSize, const std::string& text); - vtkTextActor* m_StatusActors[StatusType::NumStatusTypes]; ///> Statuses to display - DisplayCorner m_StatusDisplayCorners[StatusType::NumStatusTypes]; ///> Location (corner) of the statuses - int m_StatusFontSizes[StatusType::NumStatusTypes]; ///> Size of the statuses + vtkTextActor* m_StatusActors[static_cast<int>(StatusType::NumStatusTypes)]; ///> Statuses to display + DisplayCorner m_StatusDisplayCorners[static_cast<int>(StatusType::NumStatusTypes)]; ///> Location (corner) of the statuses + int m_StatusFontSizes[static_cast<int>(StatusType::NumStatusTypes)]; ///> Size of the statuses - VTKInteractorStyle* m_vtkInteractorStyle; ///> vtkInteractorStyle + VTKViewer* m_viewer; // Used for dimensions }; -} // end namespace imstk +} diff --git a/Source/SimulationManager/VTKRenderer/imstkVTKViewer.cpp b/Source/SimulationManager/VTKRenderer/imstkVTKViewer.cpp index d9b12fe15baabf6ad63d4895a3d8e428391d62d9..6bd28b1965be873cb02068ba5dabc231c6eaf0da 100644 --- a/Source/SimulationManager/VTKRenderer/imstkVTKViewer.cpp +++ b/Source/SimulationManager/VTKRenderer/imstkVTKViewer.cpp @@ -9,7 +9,7 @@ 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 + 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, @@ -20,69 +20,46 @@ =========================================================================*/ #include "imstkVTKViewer.h" -#include "imstkVTKRenderDelegate.h" -#include "imstkVTKInteractorStyle.h" -#include "imstkVTKRenderer.h" -#include "imstkCamera.h" +#include "imstkDeviceControl.h" #include "imstkLogger.h" #include "imstkScene.h" +#include "imstkVTKInteractorStyle.h" +#include "imstkVTKRenderer.h" +#include "imstkVTKScreenCaptureUtility.h" +#include "imstkVTKTextStatusManager.h" #include <vtkRenderer.h> #include <vtkRenderWindow.h> #include <vtkRenderWindowInteractor.h> -#include <vtkCallbackCommand.h> - -#include "imstkParallelUtils.h" +#include <vtkTextActor.h> namespace imstk { -VTKViewer::VTKViewer(SimulationManager* manager /*= nullptr*/, bool enableVR /*= false*/) : - m_enableVR(enableVR) +VTKViewer::VTKViewer(std::string name) : AbstractVTKViewer(name), + m_lastFpsUpdate(std::chrono::high_resolution_clock::now()), + m_textStatusManager(std::make_shared<VTKTextStatusManager>()), + m_lastFps(60.0) { - // init render window / interactor / command based - // depending on if we enable VR or not - if (!m_enableVR) - { - // Interactor style / commands - m_interactorStyle = std::make_shared<VTKInteractorStyle>(); - - m_vtkInteractorStyle = std::dynamic_pointer_cast<VTKInteractorStyle>(m_interactorStyle); - m_vtkInteractorStyle->m_simManager = manager; - - // Interactor - auto vtkInteractor = vtkSmartPointer<vtkRenderWindowInteractor>::New(); - vtkInteractor->SetInteractorStyle(m_vtkInteractorStyle.get()); - - // Render window - m_vtkRenderWindow = vtkSmartPointer<vtkRenderWindow>::New(); - m_vtkRenderWindow->SetInteractor(vtkInteractor); - m_vtkRenderWindow->SetSize(m_config->m_renderWinWidth, m_config->m_renderWinHeight); - - // Screen capture - m_screenCapturer = std::make_shared<VTKScreenCaptureUtility>(m_vtkRenderWindow); - } -#ifdef iMSTK_ENABLE_VR - else - { - // Interactor style / commands - m_openVRCommand = vtkSmartPointer<OpenVRCommand>::New(); - m_openVRCommand->SetSimulationManager(manager); - - // Interactor - auto vtkOpenVRinteractor = vtkSmartPointer<vtkOpenVRRenderWindowInteractor>::New(); - - // Add observer openVR command - m_vtkRenderWindow = vtkSmartPointer<vtkOpenVRRenderWindow>::New(); - m_vtkRenderWindow->SetInteractor(vtkOpenVRinteractor); - vtkOpenVRinteractor->SetRenderWindow(m_vtkRenderWindow); - m_vtkRenderWindow->AddObserver(vtkCommand::StartEvent, m_openVRCommand, 1.0); - } -#endif - - // Setup callback for timer on the interactor - timerCallbackCommand = vtkSmartPointer<vtkCallbackCommand>::New(); - timerCallbackCommand->SetCallback(timerCallback); - timerCallbackCommand->SetClientData(this); + // Create the interactor style + m_interactorStyle = std::make_shared<VTKInteractorStyle>(); + m_vtkInteractorStyle = std::dynamic_pointer_cast<vtkInteractorStyle>(m_interactorStyle); + // Bring control back out to the viewer + m_interactorStyle->setUpdateFunc([&]() { this->updateThread(); }); + + // Create the interactor + vtkNew<vtkRenderWindowInteractor> iren; + iren->SetInteractorStyle(m_vtkInteractorStyle.get()); + + // Create the RenderWindow + m_vtkRenderWindow = vtkSmartPointer<vtkRenderWindow>::New(); + m_vtkRenderWindow->SetInteractor(iren); + m_vtkRenderWindow->SetSize(m_config->m_renderWinWidth, m_config->m_renderWinHeight); + + // Screen capture + m_screenCapturer = std::make_shared<VTKScreenCaptureUtility>(m_vtkRenderWindow); + + // Setup text status + m_textStatusManager->setWindowSize(this); } void @@ -96,7 +73,7 @@ VTKViewer::setActiveScene(const std::shared_ptr<Scene>& scene) } // If the current scene has a renderer, remove it - if (m_activeScene) + if (m_activeScene != nullptr) { auto vtkRenderer = std::dynamic_pointer_cast<VTKRenderer>(this->getActiveRenderer())->getVtkRenderer(); if (m_vtkRenderWindow->HasRenderer(vtkRenderer)) @@ -111,7 +88,7 @@ VTKViewer::setActiveScene(const std::shared_ptr<Scene>& scene) // Create renderer if it doesn't exist if (!m_rendererMap.count(m_activeScene)) { - m_rendererMap[m_activeScene] = std::make_shared<VTKRenderer>(m_activeScene, m_enableVR); + m_rendererMap[m_activeScene] = std::make_shared<VTKRenderer>(m_activeScene, false); } // Cast to VTK renderer @@ -120,13 +97,30 @@ VTKViewer::setActiveScene(const std::shared_ptr<Scene>& scene) // Set renderer to renderWindow m_vtkRenderWindow->AddRenderer(vtkRenderer); - if (!m_enableVR) + // Move text actors from old to new renderer + if (m_vtkInteractorStyle->GetCurrentRenderer() != NULL) { - // Set renderer to interactorStyle - std::dynamic_pointer_cast<VTKInteractorStyle>(m_interactorStyle)->SetCurrentRenderer(vtkRenderer); + // Remove from old renderer + for (int i = 0; i < static_cast<int>(VTKTextStatusManager::StatusType::NumStatusTypes); i++) + { + m_vtkInteractorStyle->GetCurrentRenderer()->RemoveActor2D(m_textStatusManager->getTextActor(i)); + } + } + m_vtkInteractorStyle->SetCurrentRenderer(vtkRenderer); + // Add to new renderer + for (int i = 0; i < static_cast<int>(VTKTextStatusManager::StatusType::NumStatusTypes); i++) + { + vtkRenderer->AddActor2D(m_textStatusManager->getTextActor(i)); + } + + // Set name to renderWindow + m_vtkRenderWindow->SetWindowName(m_activeScene->getName().data()); - // Set name to renderWindow - m_vtkRenderWindow->SetWindowName(m_activeScene->getName().data()); + // Update the camera + std::shared_ptr<VTKRenderer> ren = std::dynamic_pointer_cast<VTKRenderer>(getActiveRenderer()); + if (ren != nullptr) + { + ren->updateCamera(); } } @@ -140,23 +134,14 @@ VTKViewer::setRenderingMode(const Renderer::Mode mode) return; } - // Setup renderer - this->getActiveRenderer()->setMode(mode, m_enableVR); - if (!m_running) + // Switch the renderer to the mode + this->getActiveRenderer()->setMode(mode, false); + if (m_status != ThreadStatus::Running) { return; } - // Render to update displayed actors - m_vtkRenderWindow->Render(); - - if (m_enableVR) - { - return; - } - - // Setup render window - //std::dynamic_pointer_cast<VTKInteractorStyle>(m_interactorStyle)->HighlightProp(nullptr); + updateThread(); if (m_config->m_hideCurzor) { @@ -174,56 +159,21 @@ VTKViewer::setRenderingMode(const Renderer::Mode mode) } } -Renderer::Mode -VTKViewer::getRenderingMode() -{ - return this->getActiveRenderer()->getMode(); -} - void -VTKViewer::startRenderingLoop() +VTKViewer::startThread() { - m_running = true; - if (!m_enableVR) + // Print all controls on viewer + for (auto control : m_controls) { - m_vtkRenderWindow->GetInteractor()->Initialize(); - m_vtkRenderWindow->GetInteractor()->CreateOneShotTimer(0); - - // If the Scene wants benchmarking hookup timer to update the table - auto vtkRen = std::dynamic_pointer_cast<VTKRenderer>(getActiveRenderer()); - vtkRen->setTimeTableVisibility(m_activeScene->getConfig()->taskTimingEnabled); - if (m_activeScene->getConfig()->taskTimingEnabled) - { - m_vtkRenderWindow->GetInteractor()->AddObserver(vtkCommand::TimerEvent, timerCallbackCommand); - m_vtkRenderWindow->GetInteractor()->CreateRepeatingTimer(500); - } - - m_vtkRenderWindow->SetWindowName(m_config->m_windowName.c_str()); - m_vtkRenderWindow->GetInteractor()->Start(); - m_vtkRenderWindow->GetInteractor()->DestroyTimer(); - } - else - { - m_vtkRenderWindow->GetInteractor()->Start(); + control->printControls(); } - m_running = false; -} - -void -VTKViewer::endRenderingLoop() -{ - // close the rendering window - m_vtkRenderWindow->Finalize(); + m_vtkRenderWindow->GetInteractor()->Initialize(); + m_vtkRenderWindow->GetInteractor()->CreateOneShotTimer(0); - // Terminate the interactor - m_vtkRenderWindow->GetInteractor()->TerminateApp(); -} - -vtkSmartPointer<vtkRenderWindow> -VTKViewer::getVtkRenderWindow() const -{ - return m_vtkRenderWindow; + m_vtkRenderWindow->SetWindowName(m_config->m_windowName.c_str()); + m_vtkRenderWindow->GetInteractor()->Start(); + m_vtkRenderWindow->GetInteractor()->DestroyTimer(); } std::shared_ptr<VTKScreenCaptureUtility> @@ -232,39 +182,71 @@ VTKViewer::getScreenCaptureUtility() const return std::static_pointer_cast<VTKScreenCaptureUtility>(m_screenCapturer); } -void -VTKViewer::setBackgroundColors(const Vec3d color1, const Vec3d color2 /*= Vec3d::Zero()*/, const bool gradientBackground /*= false*/) +std::shared_ptr<KeyboardDeviceClient> +VTKViewer::getKeyboardDevice() const +{ + return std::dynamic_pointer_cast<VTKInteractorStyle>(m_interactorStyle)->getKeyboardDeviceClient(); +} + +std::shared_ptr<MouseDeviceClient> +VTKViewer::getMouseDevice() const { - this->getActiveRenderer()->updateBackground(color1, color2, gradientBackground); + return std::dynamic_pointer_cast<VTKInteractorStyle>(m_interactorStyle)->getMouseDeviceClient(); } void -VTKViewer::setWindowTitle(const std::string& title) +VTKViewer::updateThread() { - m_config->m_windowName = title; - if (m_vtkRenderWindow) + this->postEvent(Event(EventType::PreUpdate)); + + // Update all controls + for (auto control : m_controls) { - m_vtkRenderWindow->SetWindowName(title.c_str()); + control->update(); } -} -const std::shared_ptr<VTKTextStatusManager>& -VTKViewer::getTextStatusManager() -{ - return m_vtkInteractorStyle->getTextStatusManager(); -} + std::shared_ptr<VTKRenderer> ren = std::dynamic_pointer_cast<VTKRenderer>(getActiveRenderer()); -void -VTKViewer::timerCallback(vtkObject* vtkNotUsed(caller), long unsigned int vtkNotUsed(eventId), void* clientData, void* vtkNotUsed(callData)) -{ - VTKViewer* self = static_cast<VTKViewer*>(clientData); + // Update Camera + ren->updateCamera(); + + // Update render delegates + ren->updateRenderDelegates(); + + // Reset camera clipping range + ren->getVtkRenderer()->ResetCameraClippingRange(); - if (self->getActiveScene()->getConfig()->taskTimingEnabled) + // If fps status is on, measure it + if (getTextStatusManager()->getStatusVisibility(VTKTextStatusManager::StatusType::FPS)) { - auto vtkRen = std::dynamic_pointer_cast<VTKRenderer>(self->getActiveRenderer()); - self->getActiveScene()->lockComputeTimes(); - vtkRen->setTimeTable(self->getActiveScene()->getTaskComputeTimes()); - self->getActiveScene()->unlockComputeTimes(); + // Update framerate value display + auto now = std::chrono::high_resolution_clock::now(); + double visualFPS = 1e6 / static_cast<double>(std::chrono::duration_cast<std::chrono::microseconds>(now - m_pre).count()); + visualFPS = 0.1 * visualFPS + 0.9 * m_lastFps; + m_lastFps = visualFPS; + + const int t = static_cast<int>(std::chrono::duration_cast<std::chrono::milliseconds>(now - m_lastFpsUpdate).count()); + if (t > 150) // wait 150ms before updating displayed value + { + const double physicalFPS = getActiveScene()->getFPS(); + m_textStatusManager->setFPS(visualFPS, physicalFPS); + m_lastFpsUpdate = now; + + // Update the timing table + getActiveScene()->lockComputeTimes(); + ren->setTimeTable(getActiveScene()->getTaskComputeTimes()); + getActiveScene()->unlockComputeTimes(); + } + m_pre = now; } + + // Render + getVtkRenderWindow()->GetInteractor()->Render(); + m_post = std::chrono::high_resolution_clock::now(); + + this->postEvent(Event(EventType::PostUpdate)); + + // Plan next render + getVtkRenderWindow()->GetInteractor()->CreateOneShotTimer(0); +} } -} // imstk diff --git a/Source/SimulationManager/VTKRenderer/imstkVTKViewer.h b/Source/SimulationManager/VTKRenderer/imstkVTKViewer.h index 24832d5948a19d9b7fef132cbf419bcfbcd62545..433c34bded24aa809b035ac3400d5ecc7adad5c1 100644 --- a/Source/SimulationManager/VTKRenderer/imstkVTKViewer.h +++ b/Source/SimulationManager/VTKRenderer/imstkVTKViewer.h @@ -21,72 +21,44 @@ #pragma once -#include "imstkVTKScreenCaptureUtility.h" -#include "imstkViewer.h" -#include "imstkVTKRenderDelegate.h" -#include "imstkVTKScreenCaptureUtility.h" - -#ifdef iMSTK_ENABLE_VR -#include "imstkOpenVRCommand.h" -#include "vtkOpenVRRenderWindow.h" -#include "vtkOpenVRRenderWindowInteractor.h" -#endif - -class vtkCallbackCommand; -class vtkRenderWindow; +#include "imstkAbstractVTKViewer.h" namespace imstk { -class SimulationManager; -class VTKTextStatusManager; -class VTKInteractorStyle; +class KeyboardDeviceClient; +class MouseDeviceClient; class Scene; +class VTKScreenCaptureUtility; +class VTKTextStatusManager; /// /// \class VTKViewer /// /// \brief Subclasses viewer for the VTK rendering back-end -/// Creates vtk renderer for each scene. Forwards mouse and keyboard events -/// to the vtk renderwindow +/// Creates vtk renderer for each scene. /// -class VTKViewer : public Viewer +class VTKViewer : public AbstractVTKViewer { public: - /// - /// \brief Constructor - /// \todo: SimulationManager and Viewer's should not have a circular dependence - /// - VTKViewer(SimulationManager* manager = nullptr, bool enableVR = false); - - /// - /// \brief Destructor - /// - virtual void setRenderingMode(const Renderer::Mode mode) override; - - /// - /// \brief Set scene to be rendered - /// - virtual void setActiveScene(const std::shared_ptr<Scene>& scene) override; - - /// - /// \brief Get the current renderer mode - /// - virtual Renderer::Mode getRenderingMode() override; + VTKViewer(std::string name = "VTKViewer"); + ~VTKViewer() override = default; +public: /// /// \brief Start rendering /// - virtual void startRenderingLoop() override; + void startThread() override; +public: /// - /// \brief Terminate rendering + /// \brief Set the rendering mode. In debug, debug actors will be shown. /// - virtual void endRenderingLoop() override; + void setRenderingMode(const Renderer::Mode mode) override; /// - /// \brief Get pointer to the vtkRenderWindow rendering + /// \brief Set scene to be rendered /// - vtkSmartPointer<vtkRenderWindow> getVtkRenderWindow() const; + void setActiveScene(const std::shared_ptr<Scene>& scene) override; /// /// \brief Access screen shot utility @@ -94,34 +66,34 @@ public: std::shared_ptr<VTKScreenCaptureUtility> getScreenCaptureUtility() const; /// - /// \brief Set the coloring of the screen background - /// If 'gradientBackground' is false or not supplied color1 will fill the entire background + /// \brief Return the window status handler /// - virtual void setBackgroundColors(const Vec3d color1, const Vec3d color2 = Vec3d::Zero(), - const bool gradientBackground = false) override; + std::shared_ptr<VTKTextStatusManager> getTextStatusManager() const { return m_textStatusManager; } /// - /// \brief set the window title + /// \brief Returns the device that emits key events /// - virtual void setWindowTitle(const std::string& title); + std::shared_ptr<KeyboardDeviceClient> getKeyboardDevice() const; /// - /// \brief Return the window status handler + /// \brief Returns the device that emits mouse events /// - const std::shared_ptr<VTKTextStatusManager>& getTextStatusManager(); + std::shared_ptr<MouseDeviceClient> getMouseDevice() const; protected: - /// \brief VTKTimer callback, every 500ms - static void timerCallback(vtkObject* caller, long unsigned int eventId, void* clientData, void* callData); - - vtkSmartPointer<vtkRenderWindow> m_vtkRenderWindow; - std::shared_ptr<VTKInteractorStyle> m_vtkInteractorStyle; - bool m_enableVR; + /// + /// \brief Connected to VTKs on timer event, called continously + /// and synchronously on the VTK/rendering thread + /// + void updateThread() override; - vtkSmartPointer<vtkCallbackCommand> timerCallbackCommand; +protected: + std::chrono::high_resolution_clock::time_point m_pre; ///> time point pre-rendering + std::chrono::high_resolution_clock::time_point m_post; ///> time point post-rendering + std::chrono::high_resolution_clock::time_point m_lastFpsUpdate; ///> time point for last framerate display update -#ifdef iMSTK_ENABLE_VR - vtkSmartPointer<OpenVRCommand> m_openVRCommand; -#endif + std::shared_ptr<VTKTextStatusManager> m_textStatusManager; ///> Handle text statuses, including fps status and custom text status + bool m_displayFps = false; ///> hide or display framerate + double m_lastFps; ///> last framerate value used for moving average estimate }; } // imstk diff --git a/Source/SimulationManager/VulkanRenderer/imstkVulkanViewer.cpp b/Source/SimulationManager/VulkanRenderer/imstkVulkanViewer.cpp index 0847ef572f83ac8367d5a902e8b0191b89dbfb55..221a458efc301247cf64f314b31c06c8c276e22a 100644 --- a/Source/SimulationManager/VulkanRenderer/imstkVulkanViewer.cpp +++ b/Source/SimulationManager/VulkanRenderer/imstkVulkanViewer.cpp @@ -21,12 +21,14 @@ #include "imstkVulkanViewer.h" #include "imgui_impl_glfw.h" +#include "imstkOpenVRDeviceClient.h" namespace imstk { VulkanViewer::VulkanViewer(SimulationManager* manager, bool enableVR) { m_simManager = manager; + m_config->m_enableVR = enableVR; #ifdef iMSTK_ENABLE_VR if (vr::VR_IsHmdPresent() && enableVR) @@ -121,6 +123,13 @@ VulkanViewer::startRenderingLoop() { m_renderer->m_VRMode = true; + std::shared_ptr<OpenVRDeviceClient> leftControllerDevice = std::make_shared<OpenVRDeviceClient>(OpenVRDeviceClient::DeviceType::LEFT_CONTROLLER); + m_vrDeviceClients.push_back(leftControllerDevice); + std::shared_ptr<OpenVRDeviceClient> rightControllerDevice = std::make_shared<OpenVRDeviceClient>(OpenVRDeviceClient::DeviceType::RIGHT_CONTROLLER); + m_vrDeviceClients.push_back(rightControllerDevice); + std::shared_ptr<OpenVRDeviceClient> hmdControllerDevice = std::make_shared<OpenVRDeviceClient>(OpenVRDeviceClient::DeviceType::RIGHT_CONTROLLER); + m_vrDeviceClients.push_back(hmdControllerDevice); + vr::EVRInitError error; m_renderer->m_VRSystem = vr::VR_Init(&error, vr::EVRApplicationType::VRApplication_Scene); diff --git a/Source/SceneEntities/Objects/imstkDeformableObject.cpp b/Source/SimulationManager/imstkConsoleThread.cpp similarity index 65% rename from Source/SceneEntities/Objects/imstkDeformableObject.cpp rename to Source/SimulationManager/imstkConsoleThread.cpp index d49510a0a844bf161759b65d0e48874f1c08a1db..8cb369ea73e2b33169dd119ad4fddb43e9d39135 100644 --- a/Source/SceneEntities/Objects/imstkDeformableObject.cpp +++ b/Source/SimulationManager/imstkConsoleThread.cpp @@ -19,25 +19,21 @@ =========================================================================*/ -#include "imstkFeDeformableObject.h" -#include "imstkFEMDeformableBodyModel.h" -#include "imstkLogger.h" +#include "imstkConsoleThread.h" +#include "imstkKeyboardDeviceClient.h" namespace imstk { -bool -FeDeformableObject::initialize() +ConsoleThread::ConsoleThread(std::string name) : + LoopThreadObject(name), + m_keyboardDeviceClient(KeyboardDeviceClient::New()) { - m_femModel = std::dynamic_pointer_cast<FEMDeformableBodyModel>(m_dynamicalModel); - if (m_femModel == nullptr) - { - LOG(FATAL) << "Dynamics pointer cast failure in DeformableObject::initialize()"; - return false; - } - - DynamicObject::initialize(); - m_femModel->initialize(); +} - return true; +void +ConsoleThread::updateThread() +{ + const char c = static_cast<char>(getchar()); + m_keyboardDeviceClient->emitKeyDown(c); } -} // imstk +} \ No newline at end of file diff --git a/Source/SimulationManager/imstkConsoleThread.h b/Source/SimulationManager/imstkConsoleThread.h new file mode 100644 index 0000000000000000000000000000000000000000..8e11a0d2042fb657533421ca7fe8ab3847c4b713 --- /dev/null +++ b/Source/SimulationManager/imstkConsoleThread.h @@ -0,0 +1,55 @@ +/*========================================================================= + + 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 "imstkLoopThreadObject.h" + +namespace imstk +{ +class KeyboardDeviceClient; + +/// +/// \class ConsoleThread +/// +/// \brief The console thread can run separately or in +/// sync to provide keyboard events from the console +/// they should be handled on another thread +/// +class ConsoleThread : public LoopThreadObject +{ +public: + ConsoleThread(std::string name = "ConsoleThread"); + ~ConsoleThread() override = default; + +public: + std::shared_ptr<KeyboardDeviceClient> getKeyboardDevice() const { return m_keyboardDeviceClient; } + +protected: + /// + /// \brief Awaits input + /// + void updateThread() override; + +protected: + std::shared_ptr<KeyboardDeviceClient> m_keyboardDeviceClient; +}; +} \ No newline at end of file diff --git a/Source/SimulationManager/imstkInteractorStyle.h b/Source/SimulationManager/imstkInteractorStyle.h index ed6f85225da433167437fe07484e84623967c6c9..6e42bab4e2e0e361dc2c8cceb247ec68b8e77e0b 100644 --- a/Source/SimulationManager/imstkInteractorStyle.h +++ b/Source/SimulationManager/imstkInteractorStyle.h @@ -21,17 +21,12 @@ #pragma once -#include <unordered_map> -#include <functional> +#include "imstkEventObject.h" namespace imstk { class InteractorStyle; -/// Signature of custom function called in each even callback. -/// Return true to override base class behavior, or false to maintain it. -using EventHandlerFunction = std::function<bool (InteractorStyle* iStyle)>; - /// /// \class InteractorStyle /// \brief TODO @@ -39,26 +34,18 @@ using EventHandlerFunction = std::function<bool (InteractorStyle* iStyle)>; class InteractorStyle { public: - InteractorStyle() {}; + InteractorStyle() = default; + virtual ~InteractorStyle() = default; - virtual ~InteractorStyle() {}; + /// + /// \brief Called continously + /// + void setUpdateFunc(std::function<void()> func) + { + m_updateFunc = func; + } protected: - friend class Viewer; - friend class VulkanViewer; - - /// Custom event handlers - /// Return true to override default event slot - std::unordered_map<char, EventHandlerFunction> m_onCharFunctionMap; - EventHandlerFunction m_onMouseMoveFunction; - EventHandlerFunction m_onLeftButtonDownFunction; - EventHandlerFunction m_onLeftButtonUpFunction; - EventHandlerFunction m_onMiddleButtonDownFunction; - EventHandlerFunction m_onMiddleButtonUpFunction; - EventHandlerFunction m_onRightButtonDownFunction; - EventHandlerFunction m_onRightButtonUpFunction; - EventHandlerFunction m_onMouseWheelForwardFunction; - EventHandlerFunction m_onMouseWheelBackwardFunction; - EventHandlerFunction m_onTimerFunction; + std::function<void()> m_updateFunc; }; } diff --git a/Source/SimulationManager/imstkKeyboardSceneControl.cpp b/Source/SimulationManager/imstkKeyboardSceneControl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ffe47deba77ceb30d4ab6a9d3cb845d70bd68d9e --- /dev/null +++ b/Source/SimulationManager/imstkKeyboardSceneControl.cpp @@ -0,0 +1,154 @@ +/*========================================================================= + + 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 "imstkKeyboardSceneControl.h" +#include "imstkLogger.h" +#include "imstkScene.h" +#include "imstkSceneManager.h" +#include "imstkVTKRenderer.h" +#include "imstkVTKTextStatusManager.h" +#include "imstkVTKViewer.h" + +namespace imstk +{ +KeyboardSceneControl::KeyboardSceneControl() : + m_showFps(false), m_sceneManager(nullptr), m_viewer(nullptr) +{ +} + +KeyboardSceneControl::KeyboardSceneControl(std::shared_ptr<KeyboardDeviceClient> keyDevice) : + KeyboardControl(keyDevice), + m_showFps(false), m_sceneManager(nullptr), m_viewer(nullptr) +{ +} + +void +KeyboardSceneControl::printControls() +{ + LOG(INFO) << "Keyboard Scene Controls:"; + LOG(INFO) << "----------------------------------------------------------------------"; + LOG(INFO) << " | Space - pause/resume the scene"; + LOG(INFO) << " | q/Q - stop both the scene and viewer"; + LOG(INFO) << " | d/D - toggle debug/simulation mode"; + LOG(INFO) << " | p/P - toggle visual/physics updates/second and task times display"; + LOG(INFO) << " | r/R - reset the simulation"; + LOG(INFO) << "----------------------------------------------------------------------"; +} + +void +KeyboardSceneControl::OnKeyPress(const char key) +{ + if (key == ' ') + { + if (m_sceneManager != nullptr) + { + ThreadStatus status = m_sceneManager->getStatus(); + // Pause the active scene + if (status == ThreadStatus::Running) + { + m_sceneManager->pause(true); + } + // Resume the active scene + else if (status == ThreadStatus::Paused) + { + m_sceneManager->resume(); + } + // Launch the active scene if it has yet to start + if (status == ThreadStatus::Inactive) + { + //m_textStatusManager->setStatusVisibility(VTKTextStatusManager::FPS, m_displayFps); + m_sceneManager->resume(); + } + } + } + else if (key == 'q' || key == 'Q' || key == 'e' || key == 'E') // end Simulation + { + if (m_sceneManager != nullptr && m_viewer != nullptr) + { + if (m_viewer->getStatus() != ThreadStatus::Inactive) + { + m_viewer->stop(false); + } + } + else if (m_sceneManager != nullptr && m_viewer == nullptr) + { + if (m_sceneManager->getStatus() != ThreadStatus::Inactive) + { + m_sceneManager->stop(false); + } + } + else if (m_sceneManager == nullptr && m_viewer != nullptr) + { + if (m_viewer->getStatus() != ThreadStatus::Inactive) + { + m_viewer->stop(false); + } + } + } + else if (key == 'd' || key == 'D') // switch rendering mode of the modules + { + if (m_sceneManager != nullptr && m_viewer != nullptr) + { + if (m_viewer->getRenderingMode() != Renderer::Mode::Simulation) + { + m_sceneManager->setMode(SceneManager::Mode::Simulation); + m_viewer->setRenderingMode(Renderer::Mode::Simulation); + } + else + { + m_sceneManager->setMode(SceneManager::Mode::Debug); + m_viewer->setRenderingMode(Renderer::Mode::Debug); + } + } + } + else if (key == 'p' || key == 'P') // switch framerate display + { + if (m_sceneManager != nullptr && m_viewer != nullptr) + { + // If we're dealing with a VTK viewer, flip the text visibility for FPS + std::shared_ptr<VTKViewer> vtkViewer = std::dynamic_pointer_cast<VTKViewer>(m_viewer); + if (vtkViewer != nullptr) + { + m_showFps = !m_showFps; + std::shared_ptr<VTKTextStatusManager> textManager = vtkViewer->getTextStatusManager(); + textManager->setStatusVisibility(VTKTextStatusManager::StatusType::FPS, m_showFps); + + std::shared_ptr<Scene> activeScene = m_sceneManager->getActiveScene(); + activeScene->setEnableTaskTiming(m_showFps); + const auto vtkRen = std::dynamic_pointer_cast<VTKRenderer>(m_viewer->getActiveRenderer()); + vtkRen->setTimeTableVisibility(m_showFps); + } + } + } + else if (key == 'r' || key == 'R') + { + if (m_sceneManager != nullptr) + { + m_sceneManager->getActiveScene()->reset(); + } + } +} + +void +KeyboardSceneControl::OnKeyRelease(const char imstkNotUsed(key)) +{ +} +} \ No newline at end of file diff --git a/Source/SimulationManager/imstkKeyboardSceneControl.h b/Source/SimulationManager/imstkKeyboardSceneControl.h new file mode 100644 index 0000000000000000000000000000000000000000..e3da51f910b6d53b8be7544ce08a2ef8fd82acbf --- /dev/null +++ b/Source/SimulationManager/imstkKeyboardSceneControl.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. + +=========================================================================*/ + +#pragma once + +#include "imstkKeyboardControl.h" + +namespace imstk +{ +class SceneManager; +class Viewer; + +/// +/// \class KeyboardSceneControl +/// +/// \brief This implements keyboard controls to control a scene manager and viewer +/// it may operate with both sceneManager and viewer, or only one or the other. +/// warning: This control may pause a thread. Thus it is a bad idea to process it +/// on the thread you're pausing, as you then could not resume. +/// \todo: Thread affinity +/// +class KeyboardSceneControl : public KeyboardControl +{ +public: + KeyboardSceneControl(); + KeyboardSceneControl(std::shared_ptr<KeyboardDeviceClient> keyDevice); + virtual ~KeyboardSceneControl() override = default; + +public: + void setSceneManager(std::shared_ptr<SceneManager> sceneManager) { m_sceneManager = sceneManager; } + std::shared_ptr<SceneManager> getSceneManager() const { return m_sceneManager; } + + void setViewer(std::shared_ptr<Viewer> viewer) { m_viewer = viewer; } + std::shared_ptr<Viewer> getViewer() const { return m_viewer; } + +public: + void printControls() override; + + void OnKeyPress(const char key) override; + + void OnKeyRelease(const char key) override; + +protected: + std::shared_ptr<SceneManager> m_sceneManager; + std::shared_ptr<Viewer> m_viewer; + bool m_showFps; +}; +} \ No newline at end of file diff --git a/Source/SimulationManager/imstkMouseSceneControl.cpp b/Source/SimulationManager/imstkMouseSceneControl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dbe13dff604b37af2f26a1f7fa915259af1c7343 --- /dev/null +++ b/Source/SimulationManager/imstkMouseSceneControl.cpp @@ -0,0 +1,179 @@ +/*========================================================================= + + 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 "imstkMouseSceneControl.h" +#include "imstkCamera.h" +#include "imstkLogger.h" +#include "imstkMouseDeviceClient.h" +#include "imstkScene.h" +#include "imstkSceneManager.h" + +namespace imstk +{ +MouseSceneControl::MouseSceneControl(std::shared_ptr<MouseDeviceClient> device) : MouseControl(device) +{ +} + +void +MouseSceneControl::printControls() +{ + LOG(INFO) << "Mouse Scene Controls: Only usable in debug mode"; + LOG(INFO) << "----------------------------------------------------------------------"; + LOG(INFO) << " | Left click drag - rotate view"; + LOG(INFO) << " | Middle click drag - pan view"; + LOG(INFO) << " | Scroll - zoom in/out"; + LOG(INFO) << "----------------------------------------------------------------------"; +} + +void +MouseSceneControl::OnButtonPress(const int key) +{ + // If no mode currently selected + if (m_mode == Mode::None) + { + // Set the mode + if (key == LEFT_BUTTON) + { + m_mode = Mode::Rotate; + } + else if (key == MIDDLE_BUTTON) + { + m_mode = Mode::Pan; + } + } +} + +void +MouseSceneControl::OnButtonRelease(const int key) +{ + if (key == LEFT_BUTTON && m_mode == Mode::Rotate) + { + m_mode = Mode::None; + } + else if (key == MIDDLE_BUTTON && m_mode == Mode::Pan) + { + m_mode = Mode::None; + } +} + +void +MouseSceneControl::OnScroll(const double dx) +{ + // This control is disabled in simulation mode + if (m_sceneManager->getMode() == SceneManager::Mode::Simulation) + { + return; + } + + std::shared_ptr<Camera> cam = m_sceneManager->getActiveScene()->getActiveCamera(); + const Vec3d& focalPt = cam->getFocalPoint(); + const Vec3d& camPos = cam->getPosition(); + const Vec3d diff = camPos - focalPt; + + // Linear zoom function + Vec3d newDiff; + if (dx > 0.0) + { + newDiff = diff * 1.1 * m_zoomSpeed * m_zoomFactor; + } + else + { + newDiff = diff * 0.9 * m_zoomSpeed * m_zoomFactor; + } + const Vec3d newPos = focalPt + newDiff; + cam->setPosition(newPos); + cam->update(); +} + +void +MouseSceneControl::OnMouseMove(const Vec2d& pos) +{ + // Controls disabled in simulation mode + if (m_sceneManager->getMode() == SceneManager::Mode::Simulation) + { + return; + } + + std::shared_ptr<Camera> cam = m_sceneManager->getActiveScene()->getActiveCamera(); + + // Push back the position + m_prevPos = m_pos; + m_pos = pos; + + if (m_mode == Mode::Rotate) + { + // Map mouse deltas to theta, phi rotations on a sphere + const Vec2d dx = (m_pos - m_prevPos) * (m_rotateSpeed * m_rotateFactor); + const double dTheta = dx[1]; // Elevation + const double dPhi = -dx[0]; // Azimuth + + const Vec3d& focalPt = cam->getFocalPoint(); + const Vec3d& camPos = cam->getPosition(); + Vec3d localCamPos = camPos - focalPt; + + // Get the rotation axes + const Mat4d& view = cam->getView(); + const Vec3d up = Vec3d(view(1, 0), view(1, 1), view(1, 2)); + const Vec3d right = Vec3d(view(0, 0), view(0, 1), view(0, 2)); + // Rotate around each + localCamPos = Rotd(dPhi, up).toRotationMatrix() * localCamPos; + localCamPos = Rotd(dTheta, right).toRotationMatrix() * localCamPos; + + // Set the new cam pos and up, then compute lookat + const Vec3d newPos = localCamPos + focalPt; + cam->setPosition(newPos); + cam->setViewUp(Vec3d(view(1, 0), view(1, 1), view(1, 2))); + cam->update(); + } + else if (m_mode == Mode::Pan) + { + // Move camera along up and right + const Vec2d dx = m_pos - m_prevPos; + + const Vec3d& focalPt = cam->getFocalPoint(); + const Vec3d& camPos = cam->getPosition(); + + Mat4d& view = cam->getView(); + const Vec3d up = Vec3d(view(1, 0), view(1, 1), view(1, 2)); + const Vec3d right = Vec3d(view(0, 0), view(0, 1), view(0, 2)); + + // scale pan by zoom as well + const double dist = (focalPt - camPos).norm(); + const Vec3d dPos = (up * dx[1] + right * dx[0]) * -(m_panSpeed * m_panFactor * dist); + cam->setFocalPoint(focalPt + dPos); + cam->setPosition(camPos + dPos); + cam->update(); + } +} + +void +MouseSceneControl::update() +{ + // Directly set it + //m_camera->getView() = m_targetViewTransform; + + // Slerp the camera rotation + /*const Quatd currOrientation = Quatd(m_camera->getView().block<3, 3>(0, 0)).normalized(); + const Quatd targetOrientation = Quatd(m_targetViewTransform.block<3, 3>(0, 0)).normalized(); + const Quatd newOrientation = currOrientation.slerp(0.1, targetOrientation).normalized(); + m_camera->getView().block<3, 3>(0, 0) = newOrientation.toRotationMatrix();*/ +} +} \ No newline at end of file diff --git a/Source/SimulationManager/imstkMouseSceneControl.h b/Source/SimulationManager/imstkMouseSceneControl.h new file mode 100644 index 0000000000000000000000000000000000000000..b3cb9f35fb9eea983928833e7be67d7fdcd7053a --- /dev/null +++ b/Source/SimulationManager/imstkMouseSceneControl.h @@ -0,0 +1,105 @@ +/*========================================================================= + + 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 "imstkMouseControl.h" + +namespace imstk +{ +class MouseDeviceClient; +class SceneManager; + +/// +/// \class MouseSceneControl +/// +/// \brief Controls the camera using trackball controls +/// Left click rotate, middle click pan +/// +class MouseSceneControl : public MouseControl +{ +public: + enum class Mode + { + None, + Pan, + Rotate + }; + +public: + MouseSceneControl() = default; + MouseSceneControl(std::shared_ptr<MouseDeviceClient> device); + ~MouseSceneControl() override = default; + +public: + /// + /// \brief Set the scroll controlled zoom speed + /// + void setZoomSpeed(const double zoomSpeed) { m_zoomSpeed = zoomSpeed; } + + /// + /// \brief Set the mouse controlled rotate speed + /// + void setRotateSpeed(const double rotateSpeed) { m_rotateSpeed = rotateSpeed; } + + /// + /// \brief Set the pan speed + /// + void setPanSpeed(const double panSpeed) { m_panSpeed = panSpeed; } + + /// + /// \brief Set the scene manager to be controlled + /// The active scene's camera will be controllable depending on SceneManager's mode + /// + void setSceneManager(std::shared_ptr<SceneManager> manager) { m_sceneManager = manager; } + +public: + void printControls() override; + + /// + /// \brief On the mouse scene control button press + /// + void OnButtonPress(const int key) override; + void OnButtonRelease(const int key) override; + void OnScroll(const double dx) override; + void OnMouseMove(const Vec2d& pos) override; + + // How to handle mouse movements? + // Mouse movements best done in update func or event? event would still require update for interpolation + void update() override; + +protected: + std::shared_ptr<SceneManager> m_sceneManager; + Mode m_mode = Mode::None; + Vec2d m_prevPos; + Vec2d m_pos; + + // User changeable values + double m_zoomSpeed = 1.0; + double m_rotateSpeed = 1.0; + double m_panSpeed = 1.0; + + // Hardcoded values + double m_zoomFactor = 1.0; + double m_rotateFactor = 5.0; + double m_panFactor = 1.0; +}; +} \ No newline at end of file diff --git a/Source/SimulationManager/imstkSceneManager.cpp b/Source/SimulationManager/imstkSceneManager.cpp index d77823acb907d050d66349eebbec1c560cbd7531..9be929f5271fe4379e49ff8bea9608156781eba6 100644 --- a/Source/SimulationManager/imstkSceneManager.cpp +++ b/Source/SimulationManager/imstkSceneManager.cpp @@ -19,47 +19,144 @@ =========================================================================*/ -// imstk -#include "imstkScene.h" #include "imstkSceneManager.h" -//#include "imstkCameraController.h" -#include "imstkCamera.h" +#include "imstkScene.h" +#include "imstkLogger.h" +#include "imstkDeviceControl.h" namespace imstk { -SceneManager::SceneManager(std::shared_ptr<Scene> scene) : - Module(scene->getName()), - m_scene(scene) +SceneManager::SceneManager(std::string name) : + LoopThreadObject(name), m_mode(Mode::Simulation), + m_prevCamName("default"), m_activeScene(nullptr) +{ +} + +void +SceneManager::setMode(Mode mode) +{ + if (m_mode == Mode::Simulation && mode == Mode::Debug) + { + // Store the previous camera name and switch to debug cam + m_prevCamName = + m_activeScene->getCameraName(m_activeScene->getActiveCamera()); + m_activeScene->setActiveCamera("debug"); + } + else if (m_mode == Mode::Debug && mode == Mode::Simulation) + { + // Switch back + m_activeScene->setActiveCamera(m_prevCamName); + } + m_mode = mode; +} + +bool +SceneManager::containsScene(std::string name) const +{ + return (m_sceneMap.find(name) != m_sceneMap.end()); +} + +void +SceneManager::setActiveScene(std::string name) +{ + // Check if the requested scene exists + if (!containsScene(name)) + { + LOG(WARNING) << "Scene '" << name << "' not registered! Please register before setting active"; + return; + } + // Check if the scene is already active + if (m_activeScene != nullptr && name == m_activeScene->getName()) + { + LOG(INFO) << "Scene '" << name << "' is already active!"; + return; + } + + auto newScene = this->getScene(name); + + // If the scene wants to trackFPS enable framecounting in this module + // \todo: Figure out why this can't change on the fly + if (newScene->getConfig()->trackFPS) + { + enableFrameCount(); + } + + // Pause before swapping for thread safety + ThreadStatus prevStatus = getStatus(); + if (prevStatus == ThreadStatus::Inactive + || prevStatus == ThreadStatus::Paused) + { + m_activeScene = newScene; + } + else if (prevStatus == ThreadStatus::Running) + { + // \todo: Dangerous to call this function from the thread you're about to pause + pause(true); + m_activeScene = newScene; + resume(true); + } +} + +void +SceneManager::setActiveScene(std::shared_ptr<Scene> scene) { + std::string name = scene->getName(); + + // Check if the requested scene exists + if (!containsScene(name)) + { + addScene(scene); + } + setActiveScene(name); } void -SceneManager::initModule() +SceneManager::initThread() { - m_scene->launchModules(); + if (m_activeScene != nullptr) + { + m_activeScene->initialize(); + } } void -SceneManager::cleanUpModule() +SceneManager::updateThread() { - // End Camera Controller - /// \todo move this out of scene manager - /*if (auto camController = m_scene->getCamera()->getController()) + // Advance the scene + if (m_activeScene != nullptr) { - camController->end(); - m_threadMap.at(camController->getName()).join(); - }*/ + // Process one event + doEvent(); + + m_activeScene->advance(); + } } void -SceneManager::runModule() +SceneManager::addScene(std::shared_ptr<Scene> scene) { - m_scene->advance(); -}; + if (scene == nullptr) + { + LOG(WARNING) << "Tried to add null scene!"; + return; + } + m_sceneMap[scene->getName()] = scene; +} void -SceneManager::startModuleInNewThread(std::shared_ptr<Module> module) +SceneManager::removeScene(std::string name) { - m_threadMap[module->getName()] = std::thread([module] { module->start(); }); + if (containsScene(name)) + { + std::shared_ptr<Scene> scene = m_sceneMap[name]; + if (m_activeScene == scene) + { + // \todo: Dangerous to call this function from the thread you're about to pause + pause(true); + m_activeScene = nullptr; + resume(true); + } + m_sceneMap.erase(name); + } } -} // imstk +} \ No newline at end of file diff --git a/Source/SimulationManager/imstkSceneManager.h b/Source/SimulationManager/imstkSceneManager.h index e56b932a6528c8694e51ab35665d8b3b313b48d6..73c48ddc54a826d6ff91cac45511ed3d19084cb1 100644 --- a/Source/SimulationManager/imstkSceneManager.h +++ b/Source/SimulationManager/imstkSceneManager.h @@ -21,59 +21,106 @@ #pragma once +#include "imstkLoopThreadObject.h" + #include <unordered_map> #include <thread> -#include "imstkModule.h" - namespace imstk { +class DeviceControl; class Scene; + /// /// \class SceneManager /// -/// \brief Scene manager module launches the scene in a separate thread +/// \brief Scene manager module manages multiple scenes and runs the active one /// -class SceneManager : public Module +class SceneManager : public LoopThreadObject { +public: + enum class Mode + { + Simulation, + Debug + }; + +public: + SceneManager(std::string name = "SceneManager"); + virtual ~SceneManager() override = default; + public: /// - /// \brief Constructor + /// \brief Get the scene that the scene manager is managing /// - explicit SceneManager(std::shared_ptr<Scene> scene); + std::shared_ptr<Scene> getActiveScene() const { return m_activeScene; }; /// - /// \brief Destructor + /// \brief Search for scene by name, returns nullptr if not found /// - virtual ~SceneManager() override = default; + std::shared_ptr<Scene> getScene(std::string name) const + { + if (containsScene(name)) + { + return m_sceneMap.at(name); + } + else + { + return nullptr; + } + } /// - /// \brief Get the scene that the scene manager is managing + /// \brief Get the current mode /// - std::shared_ptr<Scene> getScene() { return m_scene; }; + Mode getMode() const { return m_mode; } -protected: /// - /// \brief Initialize the module + /// \brief Switches the mode of the scene manager + /// This alters the active scene + /// + void setMode(Mode mode); + + /// + /// \brief Returns if the SceneManager contains the scene or not /// - void initModule() override; + bool containsScene(std::string name) const; /// - /// \brief Run the module + /// \brief Sets the currently updating scene /// - void runModule() override; + void setActiveScene(std::string newSceneName); /// - /// \brief Clean up the module + /// \brief Sets the currently updating scene, adds if does not exist yet /// - void cleanUpModule() override; + void setActiveScene(std::shared_ptr<Scene> scene); /// - /// \brief TODO + /// \brief Adds scene to the manager /// - void startModuleInNewThread(std::shared_ptr<Module> module); + void addScene(std::shared_ptr<Scene> scene); - std::shared_ptr<Scene> m_scene; ///> Scene that is being managed - std::unordered_map<std::string, std::thread> m_threadMap; ///> + /// + /// \brief Remove a scene from the manager + /// + void removeScene(std::string name); + +protected: + /// + /// \brief Initialize the thread + /// + void initThread() override; + + /// + /// \brief Run the thread + /// + void updateThread() override; + +protected: + std::shared_ptr<Scene> m_activeScene; ///> Scene that is being managed + std::unordered_map<std::string, std::shared_ptr<Scene>> m_sceneMap; // used in backend mode where m_sceneManagerMap is not used + Mode m_mode; + std::string m_prevCamName; }; } // imstk diff --git a/Source/SimulationManager/imstkScreenCaptureUtility.cpp b/Source/SimulationManager/imstkScreenCaptureUtility.cpp index a379219ecc0cd0db4c45d661e22d1529f5f3c440..be19bdb9e020f5a550575b9b83f97e9bfa458c6a 100644 --- a/Source/SimulationManager/imstkScreenCaptureUtility.cpp +++ b/Source/SimulationManager/imstkScreenCaptureUtility.cpp @@ -21,8 +21,6 @@ #include "imstkScreenCaptureUtility.h" -#include "imstkLogger.h" - namespace imstk { unsigned int diff --git a/Source/SimulationManager/imstkScreenCaptureUtility.h b/Source/SimulationManager/imstkScreenCaptureUtility.h index 51fd6e273cc82a9689ab7da0a5544fc17d79e85f..415265b2145dfba525da12b428f67ab88d8f87b6 100644 --- a/Source/SimulationManager/imstkScreenCaptureUtility.h +++ b/Source/SimulationManager/imstkScreenCaptureUtility.h @@ -36,7 +36,7 @@ public: /// /// \brief Saves the screenshot as a png file /// - virtual void saveScreenShot() {}; + virtual void saveScreenShot() = 0; /// /// \brief Returns the number of the screenshot @@ -55,12 +55,12 @@ protected: /// /// \brief Constructor /// - ScreenCaptureUtility() {}; + ScreenCaptureUtility() = default; /// /// \brief Destructor /// - ~ScreenCaptureUtility() = default; + virtual ~ScreenCaptureUtility() = default; unsigned int m_screenShotNumber = 0; //> screen shot number is added to the file prefix, and incremented everytime a screen shot is taken std::string m_screenShotPrefix; //> the prefix for the screenshots to be saved diff --git a/Source/SimulationManager/imstkSimulationManager.h b/Source/SimulationManager/imstkSimulationManager.h deleted file mode 100644 index ea47b59c4b7eb744111dc0ff87b6f97e596433c9..0000000000000000000000000000000000000000 --- a/Source/SimulationManager/imstkSimulationManager.h +++ /dev/null @@ -1,352 +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. - -=========================================================================*/ - -#pragma once - -#include <mutex> - -#include "imstkModule.h" - -#ifdef iMSTK_USE_Vulkan -#include "imstkVulkanViewer.h" -#else -#include "imstkVTKViewer.h" -#endif - -namespace imstk -{ -class SceneManager; -class Scene; -struct SceneConfig; -class Viewer; - -using SimulationStatus = ModuleStatus; - -template<class T> -using SceneNameMap = std::unordered_map<std::string, std::shared_ptr<T>>; - -/// -/// \brief Simulation manager mode -/// \note The mode is set at the time of initialization -/// -enum class SimulationMode -{ - /// Simulation manager launches the simulation with a - /// render window - Rendering = 0, - - /// Simulation manager launches the simulation without a - /// render window but keeps looping the simulation - RunInBackgroundSync, - - /// Simulation manager launches the simulation without a - /// render window no waiting - RunInBackgroundAsync, - - /// Simulation manager launches the simulation without a - /// render window and returns the control - Backend -}; - -/// -/// \brief Simulation manager configuration -/// -struct SimManagerConfig -{ - // logger - bool enableFileLogging = true; - bool enableStdoutLogging = true; - std::string logPath = "./"; - std::string logFilePrefix = "simulation"; - - // Name - std::string simulationName = "imstk"; - - // states - SimulationMode simulationMode = SimulationMode::Rendering; - SimulationStatus startingStatus = SimulationStatus::Running; - bool VR_Enabled = false; - bool startInPausedState = false; - - // 0 indicates that an optimal size will be used - unsigned int threadPoolSize = 0; -}; - -/// -/// \class SimulationManager -/// -/// \brief This class is the manager of the simulation at the top level. -/// The simulation can contain multiple scenes. It can be launched in three -/// modes: rendering (default), runInBackground and backend -/// -class SimulationManager -{ -using keyPressCallback = std::function<void (void)>; - -public: - /// - /// \brief Constructor - /// - SimulationManager(const std::shared_ptr<SimManagerConfig> config = std::make_shared<SimManagerConfig>()); - - /// - /// \brief Default destructor - /// - ~SimulationManager() { this->end(); }; - - /// - /// \brief Returns the simulation status - /// - const SimulationStatus& getStatus() const { return m_status; }; - - /// - /// \brief Returns log worker - /// - //std::shared_ptr<g3::LogWorker> getLogWorker() { return m_logUtil->getLogWorker(); } - - /// - /// \brief Set number of worker threads in thread pool for parallel computation - /// \param nThreads Size of the thread pool to set, - /// if nThreads <= 0 then the optimal value (which typically equals to number of logical cores) will be used - /// - void setThreadPoolSize(const int nThreads); - - /// - /// \brief Set number of worker threads in thread pool for parallel computation to be the optimal value, - /// which typically equals to the number of logical cores of the machine - /// - void setOptimalThreadPoolSize(); - - /// - /// \brief Set the viewer - /// - void setViewer(std::shared_ptr<Viewer> viewer) { m_viewer = viewer; } - - /// - /// \brief Returns true if the scene is registered, else false - /// - bool isSceneRegistered(const std::string& sceneName) const; - - /// - /// \brief Returns the scene manager given the scene - /// - std::shared_ptr<SceneManager> getSceneManager(const std::string& sceneName) const; - std::shared_ptr<SceneManager> getSceneManager(std::shared_ptr<Scene> scene) const; - - /// - /// \brief Returns the scene manager config - /// - std::shared_ptr<SimManagerConfig> getConfig() const { return m_config; } - - /// - /// \brief Returns the scene with a given name - /// - std::shared_ptr<Scene> getScene(const std::string& sceneName) const; - - /// - /// \brief Returns the scene that is currently active - /// - std::shared_ptr<Scene> getActiveScene() const; - - /// - /// \brief Create a new scene with a given name - /// - std::shared_ptr<Scene> createNewScene(const std::string& newSceneName, - std::shared_ptr<SceneConfig> config); - std::shared_ptr<Scene> createNewScene(const std::string& newSceneName); - - /// - /// \brief Create a new scene - /// \note Scene name is automatically assigned - /// - std::shared_ptr<Scene> createNewScene(); - - /// - /// \brief Add a new scene with given name to the scene list - /// - void addScene(std::shared_ptr<Scene> newScene); - - /// - /// \brief Remove the scene with given name from the scene list - /// - void removeScene(const std::string& sceneName); - - // Modules - - /// - /// \brief Returns true if the modules is registered, else false - /// - bool isModuleRegistered(const std::string& moduleName) const; - - /// - /// \brief Returns the module given the name - /// - std::shared_ptr<Module> getModule(const std::string& moduleName) const; - - /// - /// \brief Add a new module with a given name - /// - void addModule(std::shared_ptr<Module> newModule); - - /// - /// \brief Remove the module with a given name - /// - void removeModule(const std::string& moduleName); - - // Viewer - std::shared_ptr<Viewer> getViewer() const; - - /// - /// \brief Set the current scene to the one with the supplied name - /// - void setActiveScene(const std::string& newSceneName, - const bool unloadCurrentScene = false); - void setActiveScene(std::shared_ptr<Scene> scene, - const bool unloadCurrentScene = false); - - /// - /// \brief Start the simulation by initializing the active scene - /// In Mode::backend mode, the simulation manager is initialized and - /// the modules except the scene manager are launched in new threads - /// and returned. In rendering and runInBackground modes the simulation manager - /// module gets launched and an never returns - /// - void start(const SimulationStatus simStatus = SimulationStatus::Running, - const Renderer::Mode renderMode = Renderer::Mode::Simulation); - - /// - /// \brief Initialize the modules and the active scene - /// - void initialize(); - - /// - /// \brief Run the simulation from a paused state - /// In Mode::backend mode, the simulation manager is initialized if not and returned - /// - void run(); - - /// - /// \brief Pause the simulation - /// - void pause(); - - /// - /// \brief Reset the simulation to initial state - /// - void reset(); - - /// - /// \brief End the simulation - /// - void end(); - - /// - /// \brief Advance to next frame - /// - void advanceFrame(); - - /// - /// \brief Return the mode of the simulation manager - /// - SimulationMode getMode() const { return m_config->simulationMode; } - - /// - /// \brief Add key press callback to be used in background mode only - /// \todo add remove function as well - /// - void addKeyPressCallback(keyPressCallback func, const int c); - -private: - /// - /// \brief Create a viewer - /// - void createViewer(const bool enableVR); - - /// - /// \brief Start the viewer - /// - void startViewer(const Renderer::Mode renderMode = Renderer::Mode::Debug); - - /// - /// \brief Print user keyboard controls - /// - void printUserControlsInfo(const bool isRendering = true) const; - - /// - /// \brief Start a module (refer \link imstkModule \endlink) in new thread - /// - void startModuleInNewThread(std::shared_ptr<Module> module); - - /// - /// \brief Start modules - /// - void startNonSceneModules(); - - /// - /// \brief Launch scene manager modules - /// - void launchSceneModule(std::string sceneName); - - /// - /// \brief Pause modules - /// - void pauseModules(); - - /// - /// \brief End modules - /// - void endModules(); - - /// - /// \brief Keeps things in an infinite loop if rendering is disabled - /// The same keys can be used to trigger PAUSE, RUNNING, RESET of the simulation - /// - void infiniteLoopNoRenderingMode(); - - std::string m_activeSceneName = ""; - - // Maps - SceneNameMap<SceneManager> m_sceneManagerMap; - SceneNameMap<Scene> m_sceneMap; // used in backend mode where m_sceneManagerMap is not used - SceneNameMap<Module> m_modulesMap; - - std::unordered_map<std::string, std::thread> m_threadMap; - - std::shared_ptr<Viewer> m_viewer = nullptr; - - // logging - //std::shared_ptr<Logger> m_logUtil = std::make_shared<Logger>(); - std::unique_ptr<FileSinkHandle> m_fileSinkHandle; - std::unique_ptr<StdoutSinkHandle> m_stdSinkHandle; - - struct callbackKeyPair { int key; keyPressCallback func; }; - std::vector<callbackKeyPair> m_kepPressCallbacks; - - // states - SimulationStatus m_status = SimulationStatus::Inactive; - bool m_simulationStarted = false; - bool m_initialized = false; - - std::shared_ptr<SimManagerConfig> m_config; - - std::mutex m_mutex; -}; -} // imstk diff --git a/Source/SimulationManager/imstkViewer.cpp b/Source/SimulationManager/imstkViewer.cpp index 483884c6c8b23316722f74510ca6839b7d16b20d..d834d1c425308855d19fa83f040c34cbc216a1c5 100644 --- a/Source/SimulationManager/imstkViewer.cpp +++ b/Source/SimulationManager/imstkViewer.cpp @@ -20,10 +20,10 @@ =========================================================================*/ #include "imstkViewer.h" -#include "imstkScene.h" #include "imstkCamera.h" +#include "imstkDeviceControl.h" +#include "imstkInteractorStyle.h" #include "imstkLogger.h" -#include "imstkScreenCaptureUtility.h" #ifdef iMSTK_USE_Vulkan #include "imstkGUICanvas.h" @@ -31,19 +31,19 @@ namespace imstk { -Viewer::Viewer() : m_config(std::make_shared<viewerConfig>()) +Viewer::Viewer(std::string name) : + ThreadObject(name), + m_activeScene(nullptr), + m_config(std::make_shared<ViewerConfig>()), + m_debugCamera(std::make_shared<Camera>()), + m_interactorStyle(nullptr), + m_screenCapturer(nullptr) { #ifdef iMSTK_USE_Vulkan m_canvas(std::make_shared<GUIOverlay::Canvas>()) #endif } -const std::shared_ptr<Scene>& -Viewer::getActiveScene() const -{ - return m_activeScene; -} - const std::shared_ptr<Renderer>& Viewer::getActiveRenderer() const { @@ -52,90 +52,14 @@ Viewer::getActiveRenderer() const return m_rendererMap.at(m_activeScene); } -const bool& -Viewer::isRendering() const -{ - return m_running; -} - -const std::shared_ptr<ScreenCaptureUtility>& -Viewer::getScreenCaptureUtility() const -{ - return m_screenCapturer; -} - -#ifdef iMSTK_USE_Vulkan -const std::shared_ptr<GUIOverlay::Canvas>& -Viewer::getCanvas() -{ - return m_canvas; -} - -#endif - -void -Viewer::setOnCharFunction(char c, EventHandlerFunction func) -{ - m_interactorStyle->m_onCharFunctionMap[c] = func; -} - -void -Viewer::setOnMouseMoveFunction(EventHandlerFunction func) -{ - m_interactorStyle->m_onMouseMoveFunction = func; -} - -void -Viewer::setOnLeftButtonDownFunction(EventHandlerFunction func) -{ - m_interactorStyle->m_onLeftButtonDownFunction = func; -} - -void -Viewer::setOnLeftButtonUpFunction(EventHandlerFunction func) -{ - m_interactorStyle->m_onLeftButtonUpFunction = func; -} - -void -Viewer::setOnMiddleButtonDownFunction(EventHandlerFunction func) -{ - m_interactorStyle->m_onMiddleButtonDownFunction = func; -} - -void -Viewer::setOnMiddleButtonUpFunction(EventHandlerFunction func) -{ - m_interactorStyle->m_onMiddleButtonUpFunction = func; -} - -void -Viewer::setOnRightButtonDownFunction(EventHandlerFunction func) -{ - m_interactorStyle->m_onRightButtonDownFunction = func; -} - -void -Viewer::setOnRightButtonUpFunction(EventHandlerFunction func) -{ - m_interactorStyle->m_onRightButtonUpFunction = func; -} - -void -Viewer::setOnMouseWheelForwardFunction(EventHandlerFunction func) -{ - m_interactorStyle->m_onMouseWheelForwardFunction = func; -} - void -Viewer::setOnMouseWheelBackwardFunction(EventHandlerFunction func) -{ - m_interactorStyle->m_onMouseWheelBackwardFunction = func; -} - -void -Viewer::setOnTimerFunction(EventHandlerFunction func) -{ - m_interactorStyle->m_onTimerFunction = func; +Viewer::updateThread() +{ + this->postEvent(Event(EventType::PreUpdate)); + for (auto control : m_controls) + { + control->update(); + } + this->postEvent(Event(EventType::PostUpdate)); } } diff --git a/Source/SimulationManager/imstkViewer.h b/Source/SimulationManager/imstkViewer.h index be452649c3b39d883c82132f2762bdd0b768e229..01dba74dc38b93820c05cf927a4a6201b61b69ec 100644 --- a/Source/SimulationManager/imstkViewer.h +++ b/Source/SimulationManager/imstkViewer.h @@ -22,11 +22,15 @@ #pragma once #include "imstkRenderer.h" -#include "imstkInteractorStyle.h" +#include "imstkThreadObject.h" + +#include <unordered_map> namespace imstk { -class SimulationManager; +class Camera; +class DeviceControl; +class InteractorStyle; class Scene; class ScreenCaptureUtility; @@ -37,7 +41,7 @@ class Canvas; } #endif -struct viewerConfig +struct ViewerConfig { std::string m_windowName = "imstk"; @@ -57,34 +61,24 @@ struct viewerConfig /// Contains user API to configure the rendering with various backends /// Manages the keyboard and mouse events /// -class Viewer +class Viewer : public ThreadObject { +protected: + Viewer(std::string name); public: - - Viewer(); - Viewer(SimulationManager*) {} virtual ~Viewer() = default; +public: /// /// \brief Get scene currently being rendered /// - const std::shared_ptr<Scene>& getActiveScene() const; + std::shared_ptr<Scene> getActiveScene() const { return m_activeScene; } /// /// \brief Set scene to be rendered /// virtual void setActiveScene(const std::shared_ptr<Scene>& scene) = 0; - /// - /// \brief Start rendering - /// - virtual void startRenderingLoop() = 0; - - /// - /// \brief Terminate rendering - /// - virtual void endRenderingLoop() = 0; - /// /// \brief Setup the current renderer to render what's needed /// based on the mode chosen @@ -92,14 +86,14 @@ public: virtual void setRenderingMode(const Renderer::Mode mode) = 0; /// - /// \brief Get the current renderer's mode + /// \brief Set the render window size /// - virtual Renderer::Mode getRenderingMode() { return Renderer::Mode::Empty; } + virtual void setSize(int, int) { } /// - /// \brief Returns true if the Viewer is rendering + /// \brief Get the current renderer's mode /// - const bool& isRendering() const; + virtual Renderer::Mode getRenderingMode() const { return Renderer::Mode::Empty; } /// /// \brief Retrieve the renderer associated with the current scene @@ -114,7 +108,7 @@ public: /// /// \brief access screen shot utility /// - const std::shared_ptr<ScreenCaptureUtility>& getScreenCaptureUtility() const; + std::shared_ptr<ScreenCaptureUtility> getScreenCaptureUtility() const { return m_screenCapturer; } /// /// \brief Set the coloring of the screen background @@ -126,41 +120,43 @@ public: /// /// \brief Get canvas /// - const std::shared_ptr<GUIOverlay::Canvas>& getCanvas(); + std::shared_ptr<GUIOverlay::Canvas> getCanvas() const { return m_canvas; } #endif /// - /// \brief Set custom event handlers on interactor style + /// \brief Add a control whose events should be handled /// - void setOnCharFunction(char c, EventHandlerFunction func); - void setOnMouseMoveFunction(EventHandlerFunction func); - void setOnLeftButtonDownFunction(EventHandlerFunction func); - void setOnLeftButtonUpFunction(EventHandlerFunction func); - void setOnMiddleButtonDownFunction(EventHandlerFunction func); - void setOnMiddleButtonUpFunction(EventHandlerFunction func); - void setOnRightButtonDownFunction(EventHandlerFunction func); - void setOnRightButtonUpFunction(EventHandlerFunction func); - void setOnMouseWheelForwardFunction(EventHandlerFunction func); - void setOnMouseWheelBackwardFunction(EventHandlerFunction func); + void addControl(std::shared_ptr<DeviceControl> control) { m_controls.push_back(control); } /// - /// \brief Set custom behavior to be run on every frame. - /// The return of the function will not have any effect. + /// \brief Remove an existing control if it exists /// - void setOnTimerFunction(EventHandlerFunction func); + void removeControl(std::shared_ptr<DeviceControl> control) + { + std::vector<std::shared_ptr<DeviceControl>>::iterator i = + std::find(m_controls.begin(), m_controls.end(), control); + if (i != m_controls.end()) + { + m_controls.erase(i); + } + } + +protected: + virtual void updateThread(); protected: + std::vector<std::shared_ptr<DeviceControl>> m_controls; ///> Set of controls updated on the viewer thread std::unordered_map<std::shared_ptr<Scene>, std::shared_ptr<Renderer>> m_rendererMap; - std::shared_ptr<Scene> m_activeScene; + std::shared_ptr<Scene> m_activeScene; + std::shared_ptr<Camera> m_debugCamera; std::shared_ptr<InteractorStyle> m_interactorStyle; std::shared_ptr<ScreenCaptureUtility> m_screenCapturer; ///> Screen shot utility - bool m_running = false; #ifdef iMSTK_USE_Vulkan std::shared_ptr<GUIOverlay::Canvas> m_canvas = nullptr; #endif - std::shared_ptr<viewerConfig> m_config = nullptr; + std::shared_ptr<ViewerConfig> m_config; }; } diff --git a/Source/Solvers/imstkConjugateGradient.h b/Source/Solvers/imstkConjugateGradient.h index 16c3c7ec52ca29593ad778b2384782a4dc4fd2c8..62258a74cfed12dbc1c0eff083564dd0079869cd 100644 --- a/Source/Solvers/imstkConjugateGradient.h +++ b/Source/Solvers/imstkConjugateGradient.h @@ -23,7 +23,6 @@ #include "imstkIterativeLinearSolver.h" -// Eigen includes #include <Eigen/IterativeLinearSolvers> namespace imstk @@ -40,7 +39,7 @@ public: /// ConjugateGradient(); ConjugateGradient(const SparseMatrixd& A, const Vectord& rhs); - ~ConjugateGradient() = default; + virtual ~ConjugateGradient() override = default; /// /// \brief Remove specific constructor signatures diff --git a/Source/Solvers/imstkDirectLinearSolver.cpp b/Source/Solvers/imstkDirectLinearSolver.cpp index 1b82a4eb8a063a23f78be90caf956db0cad20986..9e0f1f7eb0d28b6e9883e4d468e388231cb495f9 100644 --- a/Source/Solvers/imstkDirectLinearSolver.cpp +++ b/Source/Solvers/imstkDirectLinearSolver.cpp @@ -20,9 +20,7 @@ =========================================================================*/ #include "imstkDirectLinearSolver.h" -#include "imstkLinearSystem.h" #include "imstkLogger.h" -#include <iostream> namespace imstk { diff --git a/Source/Solvers/imstkDirectLinearSolver.h b/Source/Solvers/imstkDirectLinearSolver.h index 09e3ac4ab891d1c6a9b2ed97bbf30cdc9332cf6d..bd59e940583b6f440d1faba07b18b5cc8100c352 100644 --- a/Source/Solvers/imstkDirectLinearSolver.h +++ b/Source/Solvers/imstkDirectLinearSolver.h @@ -21,16 +21,15 @@ #pragma once +#include "imstkLinearSolver.h" +#include "imstkMath.h" + #pragma warning( push ) #pragma warning( disable : 4127 ) #include <Eigen/Sparse> #include <Eigen/SparseLU> #pragma warning( pop ) -// iMSTK includes -#include "imstkLinearSolver.h" -#include "imstkMath.h" - namespace imstk { template<typename MatrixType> class DirectLinearSolver; @@ -99,8 +98,8 @@ public: /// /// \brief Default constructor/destructor /// - DirectLinearSolver() = default; - ~DirectLinearSolver() = default; + DirectLinearSolver() = default; + virtual ~DirectLinearSolver() override = default; /// /// \brief Constructor diff --git a/Source/Solvers/imstkGaussSeidel.cpp b/Source/Solvers/imstkGaussSeidel.cpp index 514fb4ca45fc5c32491d53d711e984344b1a25bd..1d36c39baf6c231eb25358a401cbe8370af47f92 100644 --- a/Source/Solvers/imstkGaussSeidel.cpp +++ b/Source/Solvers/imstkGaussSeidel.cpp @@ -21,10 +21,6 @@ #include "imstkGaussSeidel.h" #include "imstkLogger.h" -#include "imstkLinearProjectionConstraint.h" - -// Eigen includes -#include <Eigen/IterativeLinearSolvers> namespace imstk { diff --git a/Source/Solvers/imstkGaussSeidel.h b/Source/Solvers/imstkGaussSeidel.h index 4caf0cbf0a4fea7a1ab460667a4ceed43c27afe8..e3cc6eb71e52ba5ad96ed35bea3967ca8920a5de 100644 --- a/Source/Solvers/imstkGaussSeidel.h +++ b/Source/Solvers/imstkGaussSeidel.h @@ -21,7 +21,6 @@ #pragma once -// iMSTK includes #include "imstkIterativeLinearSolver.h" namespace imstk @@ -39,7 +38,7 @@ public: /// GaussSeidel() { m_type = Type::GaussSeidel; }; GaussSeidel(const SparseMatrixd& A, const Vectord& rhs); - ~GaussSeidel() = default; + virtual ~GaussSeidel() override = default; /// /// \brief Remove specific constructor signatures diff --git a/Source/Solvers/imstkIterativeLinearSolver.cpp b/Source/Solvers/imstkIterativeLinearSolver.cpp index c287f23a5b09fd4c3fe12e3c4e7e703a25d4fe35..d20bcf8a0122470f309410f78c1d5ef6efb10e75 100644 --- a/Source/Solvers/imstkIterativeLinearSolver.cpp +++ b/Source/Solvers/imstkIterativeLinearSolver.cpp @@ -21,6 +21,7 @@ #include "imstkIterativeLinearSolver.h" #include "imstkLogger.h" +#include "imstkTypes.h" namespace imstk { @@ -66,10 +67,9 @@ IterativeLinearSolver::print() const } void -IterativeLinearSolver::solve(Vectord& x) +IterativeLinearSolver::solve(Vectord& imstkNotUsed(x)) { LOG(WARNING) << "IterativeLinearSolver::solve is not implemented!"; - x; /* if (!m_linearSystem) { diff --git a/Source/Solvers/imstkIterativeLinearSolver.h b/Source/Solvers/imstkIterativeLinearSolver.h index 89d22be6fd37e932ab8eff9202418096fa752ddf..9cbfd748d8925a01de70ebe4f69872a0039f8e27 100644 --- a/Source/Solvers/imstkIterativeLinearSolver.h +++ b/Source/Solvers/imstkIterativeLinearSolver.h @@ -21,7 +21,6 @@ #pragma once -// iMSTK includes #include "imstkLinearSolver.h" namespace imstk @@ -35,8 +34,8 @@ public: /// /// \brief Default constructor/destructor /// - IterativeLinearSolver() {}; - virtual ~IterativeLinearSolver() {}; + IterativeLinearSolver() = default; + virtual ~IterativeLinearSolver() override = default; /// /// \brief Do one iteration of the method. diff --git a/Source/Solvers/imstkJacobi.cpp b/Source/Solvers/imstkJacobi.cpp index 5d7d4714dda6f2d5ba4f794204f2440f3eaea5e0..aaaabfcd494fb82ce8587784bff3a445127f9d54 100644 --- a/Source/Solvers/imstkJacobi.cpp +++ b/Source/Solvers/imstkJacobi.cpp @@ -20,11 +20,8 @@ =========================================================================*/ #include "imstkJacobi.h" -#include "imstkLogger.h" #include "imstkLinearProjectionConstraint.h" - -// Eigen includes -#include <Eigen/IterativeLinearSolvers> +#include "imstkLogger.h" namespace imstk { diff --git a/Source/Solvers/imstkJacobi.h b/Source/Solvers/imstkJacobi.h index 7d1ee27070c6d0c3479dc459ae66fc24373ae822..7c72c2b50dbb9823cc3a3f1b30638a969dfcdd97 100644 --- a/Source/Solvers/imstkJacobi.h +++ b/Source/Solvers/imstkJacobi.h @@ -38,7 +38,7 @@ public: /// Jacobi() { m_type = Type::Jacobi; }; Jacobi(const SparseMatrixd& A, const Vectord& rhs); - ~Jacobi() = default; + virtual ~Jacobi() override = default; /// /// \brief Remove specific constructor signatures diff --git a/Source/Solvers/imstkLinearSolver.h b/Source/Solvers/imstkLinearSolver.h index 7b279c1db9f4828b5996159d90acf2d98b0d1c16..1d55d8ed32f46b7cceeae9f3dfbbd84dee66ed88 100644 --- a/Source/Solvers/imstkLinearSolver.h +++ b/Source/Solvers/imstkLinearSolver.h @@ -21,7 +21,6 @@ #pragma once -// imstk includes #include "imstkLinearSystem.h" #include "imstkMath.h" @@ -53,7 +52,7 @@ public: /// \brief Default constructor/destructor /// LinearSolver() : m_linearSystem(nullptr) {}; - virtual ~LinearSolver() {}; + virtual ~LinearSolver() = default; /// /// \brief Main solve routine diff --git a/Source/Solvers/imstkLinearSystem.cpp b/Source/Solvers/imstkLinearSystem.cpp index be680e5b0a9b36d09b528a91762dfb124a4646d7..8d6f71639cd8b0c7caee8359934122e26ff5984e 100644 --- a/Source/Solvers/imstkLinearSystem.cpp +++ b/Source/Solvers/imstkLinearSystem.cpp @@ -21,8 +21,6 @@ #include "imstkLinearSystem.h" -#include <g3log/g3log.hpp> - namespace imstk { //template<typename SystemMatrixType> diff --git a/Source/Solvers/imstkLinearSystem.h b/Source/Solvers/imstkLinearSystem.h index 5c0814258a80dd0e654bbfcdaf44e4e519d12b3b..e5eb88741d2d2ed44cb89d8f6c50d8decd580dc1 100644 --- a/Source/Solvers/imstkLinearSystem.h +++ b/Source/Solvers/imstkLinearSystem.h @@ -62,7 +62,7 @@ public: /// /// \brief Destructor /// - virtual ~LinearSystem() {}; + virtual ~LinearSystem() override {}; /// /// \brief Returns a reference to local right hand side vector. diff --git a/Source/Solvers/imstkNewtonSolver.cpp b/Source/Solvers/imstkNewtonSolver.cpp index 28bf71a30b630c900b32351805baa8206d6022eb..8f11b8b70be79af9bcbf24a7215d65d9a44671b0 100644 --- a/Source/Solvers/imstkNewtonSolver.cpp +++ b/Source/Solvers/imstkNewtonSolver.cpp @@ -19,15 +19,13 @@ =========================================================================*/ -#include <iostream> -#include <memory> - #include "imstkNewtonSolver.h" -#include "imstkIterativeLinearSolver.h" #include "imstkConjugateGradient.h" #include "imstkDirectLinearSolver.h" #include "imstkLogger.h" +#include <iostream> + namespace imstk { template<> diff --git a/Source/Solvers/imstkNewtonSolver.h b/Source/Solvers/imstkNewtonSolver.h index 2dded1606af66aec5fecab42a955738777bba738..3d0cea8ee71600b0ff7852595ff881106c75ab3c 100644 --- a/Source/Solvers/imstkNewtonSolver.h +++ b/Source/Solvers/imstkNewtonSolver.h @@ -41,11 +41,11 @@ public: public: /// - /// \brief Constructors/Destructors + /// \brief Constructors\Destructors /// NewtonSolver(); - ~NewtonSolver() = default; NewtonSolver(const NewtonSolver& other) = delete; + virtual ~NewtonSolver() override = default; NewtonSolver& operator=(const NewtonSolver& other) = delete; @@ -95,7 +95,7 @@ public: /// /// \brief Get JacobianMatrix. Returns jacobian matrix /// - SystemMatrix& getJacobianMatrix(); + //SystemMatrix& getJacobianMatrix(); /// /// \brief Set AbsoluteTolerance diff --git a/Source/Solvers/imstkNonLinearSolver.cpp b/Source/Solvers/imstkNonLinearSolver.cpp index 6eac4676c94c171ba1a6e480f8ee1160401c8ffa..b7b18691b9c1099961e728243c506de1452b8c62 100644 --- a/Source/Solvers/imstkNonLinearSolver.cpp +++ b/Source/Solvers/imstkNonLinearSolver.cpp @@ -20,7 +20,6 @@ =========================================================================*/ #include "imstkNonLinearSolver.h" -#include "imstkMath.h" namespace imstk { diff --git a/Source/Solvers/imstkNonLinearSolver.h b/Source/Solvers/imstkNonLinearSolver.h index f576ea458b2376f5c8574c01976adee1bf2af6ef..af3c1cec7f2064b551ba48d0771948bdb45ed12b 100644 --- a/Source/Solvers/imstkNonLinearSolver.h +++ b/Source/Solvers/imstkNonLinearSolver.h @@ -21,15 +21,13 @@ #pragma once -// STL includes -#include <array> -#include <functional> - -// imstk includes #include "imstkNonLinearSystem.h" #include "imstkMath.h" #include "imstkSolverBase.h" +#include <array> +#include <functional> + namespace imstk { /// @@ -48,7 +46,7 @@ public: /// \brief Default Constructor/Destructor /// NonLinearSolver(); - virtual ~NonLinearSolver() = default; + virtual ~NonLinearSolver() override = default; /// /// \brief Main solve routine. diff --git a/Source/Solvers/imstkNonLinearSystem.cpp b/Source/Solvers/imstkNonLinearSystem.cpp index 0ce7bc971b8f0d85199110ca511ba94aad6d975f..fde018908fe7fca4e51ece7800f31a31412d560a 100644 --- a/Source/Solvers/imstkNonLinearSystem.cpp +++ b/Source/Solvers/imstkNonLinearSystem.cpp @@ -22,8 +22,6 @@ #include "imstkNonLinearSystem.h" #include "imstkMath.h" -// #include <g3log/g3log.hpp> - namespace imstk { template<typename Matrix> diff --git a/Source/Solvers/imstkNonLinearSystem.h b/Source/Solvers/imstkNonLinearSystem.h index 2a49cc24362b31b3c083113b11f83c76d012bac7..c6359200e4c68bf242aa50682fb8c01f01c877ca 100644 --- a/Source/Solvers/imstkNonLinearSystem.h +++ b/Source/Solvers/imstkNonLinearSystem.h @@ -22,7 +22,6 @@ #pragma once #include "imstkMath.h" -//#include "imstkLinearProjectionConstraint.h" namespace imstk { diff --git a/Source/Solvers/imstkPbdSolver.cpp b/Source/Solvers/imstkPbdSolver.cpp index a03ff5351351d8448fa6371394dc1600eaaffe29..87edaeb46e5fc0012a5ba2ce7f471f333349d79d 100644 --- a/Source/Solvers/imstkPbdSolver.cpp +++ b/Source/Solvers/imstkPbdSolver.cpp @@ -20,7 +20,9 @@ =========================================================================*/ #include "imstkPbdSolver.h" +#include "imstkLogger.h" #include "imstkParallelUtils.h" +#include "imstkPbdCollisionConstraint.h" namespace imstk { @@ -32,6 +34,19 @@ PbdSolver::PbdSolver() : { } +void +PbdSolver::setSolverType(const PbdConstraint::SolverType& type) +{ + if (type == PbdConstraint::SolverType::GCD) + { + LOG(WARNING) << "GCD is NOT implemented yet, use xPBD instead"; + m_solverType = PbdConstraint::SolverType::xPBD; + return; + } + + m_solverType = type; +} + void PbdSolver::solve() { diff --git a/Source/Solvers/imstkPbdSolver.h b/Source/Solvers/imstkPbdSolver.h index 73feaf9fef5a47026dde13638737f3b9ec5f4fcf..3e873bbf7be6519a3d096457e9378e5141abf5c7 100644 --- a/Source/Solvers/imstkPbdSolver.h +++ b/Source/Solvers/imstkPbdSolver.h @@ -21,13 +21,13 @@ #pragma once -#include "imstkPbdCollisionConstraint.h" #include "imstkPbdConstraint.h" #include "imstkSolverBase.h" -#include "imstkLogger.h" namespace imstk { +class PbdCollisionConstraint; + /// /// \struct CollisionConstraintData /// \brief Stores positions and masses of two colliding objects @@ -105,17 +105,7 @@ public: /// /// \brief Set the PBD solver type /// - void setSolverType(const PbdConstraint::SolverType& type) - { - if (type == PbdConstraint::SolverType::GCD) - { - LOG(WARNING) << "GCD is NOT implemented yet, use xPBD instead"; - m_solverType = PbdConstraint::SolverType::xPBD; - return; - } - - m_solverType = type; - } + void setSolverType(const PbdConstraint::SolverType& type); /// /// \brief Solve the non linear system of equations G(x)=0 using Newton's method. @@ -155,7 +145,7 @@ public: /// /// \brief Add the global collision contraints to this solver /// - void addCollisionConstraints(PBDCollisionConstraintVector* constraints, + void addCollisionConstraints(std::vector<PbdCollisionConstraint*>* constraints, std::shared_ptr<StdVectorOfVec3d> posA, std::shared_ptr<StdVectorOfReal> invMassA, std::shared_ptr<StdVectorOfVec3d> posB, std::shared_ptr<StdVectorOfReal> invMassB); @@ -165,9 +155,9 @@ public: void solve() override; private: - size_t m_collisionIterations = 5; ///> Number of NL Gauss-Seidel iterations for collision constraints + size_t m_collisionIterations = 5; ///> Number of NL Gauss-Seidel iterations for collision constraints - std::shared_ptr<std::list<PBDCollisionConstraintVector*>> m_collisionConstraints = nullptr; ///< Collision contraints charged to this solver - std::shared_ptr<std::list<CollisionConstraintData>> m_collisionConstraintsData = nullptr; + std::shared_ptr<std::list<std::vector<PbdCollisionConstraint*>*>> m_collisionConstraints = nullptr; ///< Collision contraints charged to this solver + std::shared_ptr<std::list<CollisionConstraintData>> m_collisionConstraintsData = nullptr; }; } // imstk diff --git a/Source/Solvers/imstkProjectedGaussSeidelSolver.h b/Source/Solvers/imstkProjectedGaussSeidelSolver.h new file mode 100644 index 0000000000000000000000000000000000000000..c833eaa83b35fc72a515b3f0b791a45ac1af354a --- /dev/null +++ b/Source/Solvers/imstkProjectedGaussSeidelSolver.h @@ -0,0 +1,88 @@ +/*========================================================================= + + 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 "imstkMath.h" + +namespace imstk +{ +template<typename Scalar> +class ProjectedGaussSeidelSolver +{ +public: + // Sets the vector to be used for the solve + //void setGuess(Matrix<Scalar, -1, 1>& g) { x = g; } + void setA(Eigen::SparseMatrix<Scalar>* A) { this->m_A = A; } + void setMaxIterations(const unsigned int maxIterations) { this->m_maxIterations = maxIterations; } + void setRelaxation(const Scalar relaxation) { this->m_relaxation = relaxation; } + + Eigen::Matrix<Scalar, -1, 1>& solve(const Eigen::Matrix<Scalar, -1, 1>& b, const Eigen::Matrix<Scalar, -1, 2>& cu) + { + const Eigen::SparseMatrix<Scalar>& A = *m_A; + + // Allocate new results + m_x = Eigen::Matrix<Scalar, -1, 1>(b.rows()); + m_x.setZero(); + + // Naive implementation of PGS + // Consider graph coloring and TBB parallizing + Eigen::Matrix<Scalar, -1, 1> xOld; + for (unsigned int i = 0; i < m_maxIterations; i++) + { + xOld = m_x; + for (Eigen::Index r = 0; r < A.rows(); r++) + { + Scalar delta = 0.0; + + // Sum up rows (skip r) + for (Eigen::Index c = 0; c < r; c++) + { + delta += A.coeff(r, c) * m_x[c]; + } + for (Eigen::Index c = r + 1; c < A.cols(); c++) + { + delta += A.coeff(r, c) * m_x[c]; + } + + delta = (b[r] - delta) / A.coeff(r, r); + // Apply relaxation factor + m_x(r) += m_relaxation * (delta - m_x(r)); + // Do projection *every iteration* + m_x(r) = std::min(cu(r, 1), std::max(cu(r, 0), m_x(r))); + } + + // Check convergence + if ((m_x - xOld).norm() < 1.0e-4) + { + return m_x; + } + } + + return m_x; + } + +private: + unsigned int m_maxIterations = 3; + Scalar m_relaxation = static_cast<Scalar>(0.1); + Eigen::Matrix<Scalar, -1, 1> m_x; ///> Results + Eigen::SparseMatrix<Scalar>* m_A = nullptr; +}; +} \ No newline at end of file diff --git a/Source/Solvers/imstkSOR.h b/Source/Solvers/imstkSOR.h index d71a93fd9af8aeea16b06a432ab856f6723d3c0e..88b89b72913523fa3500607ca4e9a7324a2b3d36 100644 --- a/Source/Solvers/imstkSOR.h +++ b/Source/Solvers/imstkSOR.h @@ -21,11 +21,9 @@ #pragma once -// iMSTK includes #include "imstkNonLinearSystem.h" #include "imstkIterativeLinearSolver.h" -// Eigen includes #include <Eigen/IterativeLinearSolvers> namespace imstk @@ -43,7 +41,7 @@ public: /// SOR(const double relaxationFactor = 0.5) : m_relaxationFactor(relaxationFactor) { m_type = Type::SuccessiveOverRelaxation; }; SOR(const SparseMatrixd& A, const Vectord& rhs); - ~SOR() = default; + virtual ~SOR() override = default; /// /// \brief Remove specific constructor signatures diff --git a/Source/apiUtilities/imstkAPIUtilities.cpp b/Source/apiUtilities/imstkAPIUtilities.cpp index 3dcf882c6757e8e78c1157ca62b889715539bc17..6351de87c00b2254d136be152eca23b59fbef77e 100644 --- a/Source/apiUtilities/imstkAPIUtilities.cpp +++ b/Source/apiUtilities/imstkAPIUtilities.cpp @@ -19,38 +19,25 @@ =========================================================================*/ #include "imstkAPIUtilities.h" +#include "imstkGraph.h" +#include "imstkLinearProjectionConstraint.h" +#include "imstkLogger.h" // Objects -#include "imstkFEMDeformableBodyModel.h" -#include "imstkSceneObject.h" -#include "imstkSceneManager.h" #include "imstkCollidingObject.h" +#include "imstkFEMDeformableBodyModel.h" #include "imstkScene.h" - -#include "imstkColor.h" - -// Solvers -#include "imstkNonLinearSystem.h" +#include "imstkSceneManager.h" // Geometry -#include "imstkPlane.h" -#include "imstkSphere.h" #include "imstkCapsule.h" #include "imstkCube.h" -#include "imstkPointSet.h" +#include "imstkImageData.h" +#include "imstkMeshIO.h" +#include "imstkPlane.h" +#include "imstkSphere.h" #include "imstkSurfaceMesh.h" #include "imstkTetrahedralMesh.h" -#include "imstkMeshIO.h" -#include "imstkImageData.h" - -#include "imstkGraph.h" -#include "imstkCollisionGraph.h" -#include "imstkCamera.h" -#include "imstkLinearProjectionConstraint.h" - -// logger -#include "imstkLogger.h" -#include "imstkTimer.h" namespace imstk { @@ -211,11 +198,13 @@ printUPS(std::shared_ptr<SceneManager> sceneManager) } sceneManager->enableFrameCount(); - sceneManager->setPostUpdateCallback([&sceneManager](Module* module) + // When sceneManager emits PreUpdate, cout the ups + connect<Event>(sceneManager, EventType::PreUpdate, + [&sceneManager](Event*) { - std::cout << "\r" << module->getName() << " running at " + std::cout << "\r" << sceneManager->getName() << " running at " << sceneManager->getUPS() << " ups " << std::flush; - }); + }); } std::shared_ptr<Graph> diff --git a/Source/apiUtilities/imstkAPIUtilities.h b/Source/apiUtilities/imstkAPIUtilities.h index e1ee8ddae31321d422fdc44d08c759925fc603fb..4b15f5cfd9f7f49f3075f21936f90f1f6dbf3597 100644 --- a/Source/apiUtilities/imstkAPIUtilities.h +++ b/Source/apiUtilities/imstkAPIUtilities.h @@ -22,32 +22,32 @@ #pragma once #include "imstkGeometry.h" -#include "imstkSceneObject.h" #include "imstkMath.h" namespace imstk { -class TetrahedralMesh; -class SurfaceMesh; -class PointSet; -class SceneManager; -class Scene; +class CollidingObject; class FEMDeformableBodyModel; +class Graph; template<typename Matrix> class NonLinearSystem; -class CollidingObject; -class Graph; +class PointSet; +class Scene; +class SceneManager; +class SceneObject; +class SurfaceMesh; +class TetrahedralMesh; namespace apiutils { /// /// \brief Create a analytical visual scene object that and add it to the scene /// -std::shared_ptr<VisualObject> createVisualAnalyticalSceneObject(Geometry::Type type, - std::shared_ptr<Scene> scene, - const std::string& objName, - const double scale = 1., - const Vec3d t = Vec3d(0., 0., 0.)); +std::shared_ptr<SceneObject> createVisualAnalyticalSceneObject(Geometry::Type type, + std::shared_ptr<Scene> scene, + const std::string& objName, + const double scale = 1., + const Vec3d t = Vec3d(0., 0., 0.)); /// /// \brief Create a analytical colliding scene object that and add it to the scene diff --git a/Source/apiUtilities/imstkPlotterUtils.cpp b/Source/apiUtilities/imstkPlotterUtils.cpp index 28af152b647d667477184d81c08e1bd1c6fe5341..305ac6780b3d7a6cd6723c2149a6d6418f1a0398 100644 --- a/Source/apiUtilities/imstkPlotterUtils.cpp +++ b/Source/apiUtilities/imstkPlotterUtils.cpp @@ -18,4 +18,144 @@ limitations under the License. =========================================================================*/ -#include "imstkPlotterUtils.h" \ No newline at end of file + +#include "imstkPlotterUtils.h" +#include "imstkLogger.h" + +namespace imstk +{ +namespace plotterutils +{ +void +writePlotterVectorMatlab(Vectord& x, const char* fileName) +{ + std::ofstream scriptFile(fileName); + + CHECK(scriptFile.is_open()) << "Unable to create or open the specified file for plot script!"; + + // print x + scriptFile << "X=[\n"; + for (auto i = 0; i < x.size(); ++i) + { + scriptFile << x[i] << "\n"; + } + scriptFile << "];\n"; + + // plot x + scriptFile << "plot(X, 'r-', 'LineWidth', 2, 'MarkerSize', 10);\n"; + scriptFile.close(); +} + +/// +/// \brief Write a Matlab script to plot X vs Y where X, Y are input vectors of same size +/// +void +writePlotterVecVsVecMatlab(Vectord& x, Vectord& y, const char* fileName) +{ + // check if the vectors are of the same size + if (x.size() != y.size()) + { + LOG(WARNING) << "The vectors supplied for plotting are not of same size!"; + return; + } + + std::ofstream scriptFile(fileName); + + CHECK(scriptFile.is_open()) << "Unable to create or open the specified file for plot script!"; + + // print x + scriptFile << "X=[\n"; + for (auto i = 0; i < x.size(); ++i) + { + scriptFile << x[i] << "\n"; + } + scriptFile << "];\n"; + + // print y + scriptFile << "Y=[\n"; + for (auto i = 0; i < y.size(); ++i) + { + scriptFile << y[i] << "\n"; + } + scriptFile << "];\n"; + + // plot x vs y + scriptFile << "plot(X, Y, 'r-', 'LineWidth', 2, 'MarkerSize', 10);\n"; + scriptFile.close(); +} + +/// +/// \brief Write a MatPlotlib script to plot a given vector +/// +void +writePlotterVectorMatPlotlib(Vectord& x, const char* fileName) +{ + std::ofstream scriptFile(fileName); + + CHECK(scriptFile.is_open()) << "Unable to create or open the specified file for plot script!"; + + // import + scriptFile << "import numpy as np\n"; + scriptFile << "import matplotlib.pyplot as plt\n"; + + // print x + scriptFile << "X=[\n"; + for (auto i = 0; i < x.size(); ++i) + { + scriptFile << x[i] << ",\n"; + } + scriptFile << "];\n"; + + // plot + scriptFile << "plt.plot(X, 'ro')\n"; + + // show the plot + scriptFile << "plt.show()\n"; +} + +/// +/// \brief Write a MatPlotlib script to plot \p x vs \p y where \p x, \p y are of same +/// size +/// +void +writePlotterVecVsVecMatPlotlib(Vectord& x, Vectord& y, const char* fileName) +{ + // check if the vectors are of the same size + if (x.size() != y.size()) + { + LOG(WARNING) << "The vectors supplied for plotting are not of same size!"; + return; + } + + std::ofstream scriptFile(fileName); + + CHECK(scriptFile.is_open()) << "Unable to create or open the specified file for plot script!"; + + // import + scriptFile << "import numpy as np\n"; + scriptFile << "import matplotlib.pyplot as plt\n"; + + // print x + scriptFile << "X=[\n"; + for (auto i = 0; i < x.size(); ++i) + { + scriptFile << x[i] << ",\n"; + } + scriptFile << "];\n"; + + // print y + scriptFile << "Y=[\n"; + for (auto i = 0; i < y.size(); ++i) + { + scriptFile << y[i] << ",\n"; + } + scriptFile << "];\n"; + + // plot + scriptFile << "plt.plot(X, Y, 'ro')\n"; + + // show the plot + scriptFile << "plt.show()\n"; +} +} +} \ No newline at end of file diff --git a/Source/apiUtilities/imstkPlotterUtils.h b/Source/apiUtilities/imstkPlotterUtils.h index d592c7665ac3bd65a9395863f709a0e522ce76f6..828a4f28ac27144f7e46a42154a3dc9a45fb2097 100644 --- a/Source/apiUtilities/imstkPlotterUtils.h +++ b/Source/apiUtilities/imstkPlotterUtils.h @@ -21,13 +21,7 @@ #pragma once -// STL includes -#include <iostream> -#include <fstream> - -// imstk #include "imstkMath.h" -#include "imstkLogger.h" #pragma warning( push ) #pragma warning( disable : 4505 ) // Warning C4505 will vanish upon calls to the following functions @@ -38,137 +32,23 @@ namespace plotterutils /// /// \brief Write a Matlab script to plot a given vector /// -static void -writePlotterVectorMatlab(Vectord& x, const char* fileName) -{ - std::ofstream scriptFile(fileName); - - CHECK(scriptFile.is_open()) << "Unable to create or open the specified file for plot script!"; - - // print x - scriptFile << "X=[\n"; - for (auto i = 0; i < x.size(); ++i) - { - scriptFile << x[i] << "\n"; - } - scriptFile << "];\n"; - - // plot x - scriptFile << "plot(X, 'r-', 'LineWidth', 2, 'MarkerSize', 10);\n"; - scriptFile.close(); -} +void writePlotterVectorMatlab(Vectord& x, const char* fileName); /// /// \brief Write a Matlab script to plot X vs Y where X, Y are input vectors of same size /// -static void -writePlotterVecVsVecMatlab(Vectord& x, Vectord& y, const char* fileName) -{ - // check if the vectors are of the same size - if (x.size() != y.size()) - { - LOG(WARNING) << "The vectors supplied for plotting are not of same size!"; - return; - } - - std::ofstream scriptFile(fileName); - - CHECK(scriptFile.is_open()) << "Unable to create or open the specified file for plot script!"; - - // print x - scriptFile << "X=[\n"; - for (auto i = 0; i < x.size(); ++i) - { - scriptFile << x[i] << "\n"; - } - scriptFile << "];\n"; - - // print y - scriptFile << "Y=[\n"; - for (auto i = 0; i < y.size(); ++i) - { - scriptFile << y[i] << "\n"; - } - scriptFile << "];\n"; - - // plot x vs y - scriptFile << "plot(X, Y, 'r-', 'LineWidth', 2, 'MarkerSize', 10);\n"; - scriptFile.close(); -} +void writePlotterVecVsVecMatlab(Vectord& x, Vectord& y, const char* fileName); /// /// \brief Write a MatPlotlib script to plot a given vector /// -static void -writePlotterVectorMatPlotlib(Vectord& x, const char* fileName) -{ - std::ofstream scriptFile(fileName); - - CHECK(scriptFile.is_open()) << "Unable to create or open the specified file for plot script!"; - - // import - scriptFile << "import numpy as np\n"; - scriptFile << "import matplotlib.pyplot as plt\n"; - - // print x - scriptFile << "X=[\n"; - for (auto i = 0; i < x.size(); ++i) - { - scriptFile << x[i] << ",\n"; - } - scriptFile << "];\n"; - - // plot - scriptFile << "plt.plot(X, 'ro')\n"; - - // show the plot - scriptFile << "plt.show()\n"; -} +void writePlotterVectorMatPlotlib(Vectord& x, const char* fileName); /// /// \brief Write a MatPlotlib script to plot \p x vs \p y where \p x, \p y are of same /// size /// -static void -writePlotterVecVsVecMatPlotlib(Vectord& x, Vectord& y, const char* fileName) -{ - // check if the vectors are of the same size - if (x.size() != y.size()) - { - LOG(WARNING) << "The vectors supplied for plotting are not of same size!"; - return; - } - - std::ofstream scriptFile(fileName); - - CHECK(scriptFile.is_open()) << "Unable to create or open the specified file for plot script!"; - - // import - scriptFile << "import numpy as np\n"; - scriptFile << "import matplotlib.pyplot as plt\n"; - - // print x - scriptFile << "X=[\n"; - for (auto i = 0; i < x.size(); ++i) - { - scriptFile << x[i] << ",\n"; - } - scriptFile << "];\n"; - - // print y - scriptFile << "Y=[\n"; - for (auto i = 0; i < y.size(); ++i) - { - scriptFile << y[i] << ",\n"; - } - scriptFile << "];\n"; - - // plot - scriptFile << "plt.plot(X, Y, 'ro')\n"; - - // show the plot - scriptFile << "plt.show()\n"; -} +void writePlotterVecVsVecMatPlotlib(Vectord& x, Vectord& y, const char* fileName); } // plotters } // imstk