Modifying levelsets with analytical sphere

Hello,
I’m trying to make a drill tool with spherical drill head and was wondering if it is possible to modify the level set with just a sphere instead of a spherical surface mesh with lots of vertices.

I am assuming you are going by the FemurCutExample, we haven’t visited this feature set in a while but i didn’t see anything that limits you to the geometry, as far as i can tell. The collision handling code is in LevelSetCH is concerned with collision data which is somewhat independent of the collision geometry.

As i said we haven’t visited this in a while, if there are any major issues with this complex i may not be able to help you much. For example RigidObjectLevelSetCollision still uses the RigidObject2 class which has been superseded by the PBD Rigid Body implementation.

Yes, im referring to the femur cut example.

if you change the makeRigidObj to create and use a Sphere object for its CollidingGeometry it crashes because a sphere is AnalyticalGeometry and SurfaceMesh is a PointSet. the collision logic requires it to be a point set to modify the level set.

you can modify lines around 69 like so,

    auto sphere = std::make_shared<Sphere>(Vec3d(0.0, 0.0, 0.0), 0.002);

    // Create the object
    rigidObj->setVisualGeometry(toolMesh);
    rigidObj->setPhysicsGeometry(toolMesh);
    rigidObj->setCollidingGeometry(sphere);
    rigidObj->setDynamicalModel(rbdModel);
    rigidObj->getVisualModel(0)->setRenderMaterial(material);
    rigidObj->getRigidBody()->m_mass = 10.0;
    rigidObj->getRigidBody()->m_intertiaTensor = Mat3d::Identity() * 10000.0;
    rigidObj->getRigidBody()->m_initPos = Vec3d(0.0, 1.0, 2.0);

because my tool tip is a perfect sphere, i want to instead use either a sphere to collide with the level set, or a mesh with a single vertex but over a large radius.
I tried increasing the cutting collision’s handler kernel size to about 9 or so and it crashed, probably because of temp allocator running out of memory? I have a large resolution volume of 256x256x256.

I see, i did find the spot in LevelSetCH where we require the PointSet. If you have a scene and you can collide with the volume without crashing (when cutting is disabled), my guess would be that the crash is not really related to memory, increasing the kernel size adds to the number of calls made to addImpulse() which is called from LevelSetCH [here] (https://gitlab.kitware.com/iMSTK/iMSTK/-/blob/master/Source/CollisionHandling/imstkLevelSetCH.cpp#L153).

Is the crash caused by a CHECK assertion, do you have a log or do you just see a system message ? There might be other issues or bugs from calculating an index incorrectly in imstk, trying to debug at the site where it crashes might give an indication of what’s going on

Ive prepared a repro example, but im unable to upload its zip file here. is there any way i can send it over?

each time i run with kernel size 13 it seem to crash randomly at different places, not necessarily in imstk’s source.
it also crashes at random times, sometimes it happens immediately when i touch the surface, sometimes when i drill the levelset for a few seconds.

here are callstacks for 3 crashes

ntdll.dll!00007ff84c26f1d2()
ntdll.dll!00007ff84c277f92()
ntdll.dll!00007ff84c27827a()
ntdll.dll!00007ff84c27df01()
ntdll.dll!00007ff84c195bf0()
ntdll.dll!00007ff84c1947b1()
ucrtbase.dll!00007ff849bff05b()
[Inline Frame] Example-Drilling.exe!std::_Deallocate(void *) Line 258
	at C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.40.33807\include\xmemory(258)
[Inline Frame] Example-Drilling.exe!std::_Default_allocator_traits<std::allocator<std::_List_node<int,void *>>>::deallocate(std::allocator<std::_List_node<int,void *>> &) Line 691
	at C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.40.33807\include\xmemory(691)
[Inline Frame] Example-Drilling.exe!std::_List_node<int,void *>::_Freenode0(std::allocator<std::_List_node<int,void *>> &) Line 312
	at C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.40.33807\include\list(312)
[Inline Frame] Example-Drilling.exe!std::_List_node<int,void *>::_Freenode(std::allocator<std::_List_node<int,void *>> &) Line 318
	at C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.40.33807\include\list(318)
[Inline Frame] Example-Drilling.exe!std::_List_node<int,void *>::_Free_non_head(std::allocator<std::_List_node<int,void *>> & _Head, std::_List_node<int,void *> *) Line 329
	at C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.40.33807\include\list(329)
[Inline Frame] Example-Drilling.exe!std::list<int,std::allocator<int>>::_Tidy() Line 1503
	at C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.40.33807\include\list(1503)
[Inline Frame] Example-Drilling.exe!std::list<int,std::allocator<int>>::{dtor}() Line 1048
	at C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.40.33807\include\list(1048)
[Inline Frame] Example-Drilling.exe!std::_Default_allocator_traits<std::allocator<std::unordered_set<int,std::hash<int>,std::equal_to<int>,std::allocator<int>>>>::destroy(std::allocator<std::unordered_set<int,std::hash<int>,std::equal_to<int>,std::allocator<int>>> &) Line 709
	at C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.40.33807\include\xmemory(709)
[Inline Frame] Example-Drilling.exe!std::_Destroy_range(std::unordered_set<int,std::hash<int>,std::equal_to<int>,std::allocator<int>> * _First, std::unordered_set<int,std::hash<int>,std::equal_to<int>,std::allocator<int>> * const _Last, std::allocator<std::unordered_set<int,std::hash<int>,std::equal_to<int>,std::allocator<int>>> &) Line 1068
	at C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.40.33807\include\xmemory(1068)
Example-Drilling.exe!std::vector<std::unordered_set<int,std::hash<int>,std::equal_to<int>,std::allocator<int>>,std::allocator<std::unordered_set<int,std::hash<int>,std::equal_to<int>,std::allocator<int>>>>::clear() Line 1778
	at C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.40.33807\include\vector(1778)
Example-Drilling.exe!imstk::AbstractCellMesh::clear() Line 17
	at D:\Work\iMSTK\Source\Geometry\Mesh\imstkAbstractCellMesh.cpp(17)
Example-Drilling.exe!imstk::CellMesh<3>::clear() Line 55
	at D:\Work\iMSTK\Source\Geometry\Mesh\imstkCellMesh.h(55)
Example-Drilling.exe!imstk::CellMesh<3>::initialize(std::shared_ptr<imstk::VecDataArray<double,3>> vertices, std::shared_ptr<imstk::VecDataArray<int,3>> indices) Line 41
	at D:\Work\iMSTK\Source\Geometry\Mesh\imstkCellMesh.h(41)
Example-Drilling.exe!imstk::SurfaceMesh::initialize(std::shared_ptr<imstk::VecDataArray<double,3>> vertices, std::shared_ptr<imstk::VecDataArray<int,3>> triangleIndices, const bool computeDerivedData) Line 21
	at D:\Work\iMSTK\Source\Geometry\Mesh\imstkSurfaceMesh.cpp(21)
Example-Drilling.exe!imstk::mcSubImage(std::shared_ptr<imstk::ImageData> imageData, std::shared_ptr<imstk::SurfaceMesh> outputSurf, const Eigen::Matrix<int,3,1,0,3,1> & start, const Eigen::Matrix<int,3,1,0,3,1> & end, const double isoValue) Line 583
	at D:\Work\iMSTK\Source\Filtering\imstkLocalMarchingCubes.cpp(583)
Example-Drilling.exe!imstk::LocalMarchingCubes::requestUpdate() Line 707
	at D:\Work\iMSTK\Source\Filtering\imstkLocalMarchingCubes.cpp(707)
Example-Drilling.exe!imstk::GeometryAlgorithm::update() Line 83
	at D:\Work\iMSTK\Source\FilteringCore\imstkGeometryAlgorithm.h(83)
Example-Drilling.exe!FemurObject::visualUpdate() Line 176
	at D:\Work\iMSTK\Examples\Drilling\Drilling.cpp(176)
Example-Drilling.exe!imstk::Scene::updateVisuals(const double dt) Line 606
	at D:\Work\iMSTK\Source\Scene\imstkScene.cpp(606)
Example-Drilling.exe!imstk::VTKViewer::updateModule() Line 216
	at D:\Work\iMSTK\Source\ViewerVTK\imstkVTKViewer.cpp(216)
Example-Drilling.exe!imstk::Module::update() Line 38
	at D:\Work\iMSTK\Source\Common\imstkModule.cpp(38)
Example-Drilling.exe!imstk::SimulationManager::start() Line 166
	at D:\Work\iMSTK\Source\SimulationManager\imstkSimulationManager.cpp(166)
Example-Drilling.exe!main() Line 424
	at D:\Work\iMSTK\Examples\Drilling\Drilling.cpp(424)
[Inline Frame] Example-Drilling.exe!invoke_main() Line 78
	at D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl(78)
Example-Drilling.exe!__scrt_common_main_seh() Line 288
	at D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl(288)
kernel32.dll!00007ff84a3c7034()
ntdll.dll!00007ff84c1c2651()

vtkCommonDataModel-9.1.dll!00007fff5574b814()
vtkCommonDataModel-9.1.dll!00007fff55754a62()
vtkCommonExecutionModel-9.1.dll!00007fff559b1e7b()
vtkCommonExecutionModel-9.1.dll!00007fff5596510d()
vtkCommonExecutionModel-9.1.dll!00007fff5597153d()
vtkCommonExecutionModel-9.1.dll!00007fff55973db5()
vtkCommonExecutionModel-9.1.dll!00007fff55973bbc()
vtkCommonExecutionModel-9.1.dll!00007fff55973c9c()
vtkCommonExecutionModel-9.1.dll!00007fff5596aa72()
vtkRenderingCore-9.1.dll!00007fff561c97b4()
vtkRenderingOpenGL2-9.1.dll!00007fff56d5fd69()
vtkRenderingCore-9.1.dll!00007fff5614e517()
vtkRenderingCore-9.1.dll!00007fff561deeb8()
vtkRenderingOpenGL2-9.1.dll!00007fff56db2ad1()
vtkRenderingOpenGL2-9.1.dll!00007fff56db5084()
vtkRenderingOpenGL2-9.1.dll!00007fff56db2851()
vtkRenderingCore-9.1.dll!00007fff561dce08()
vtkRenderingCore-9.1.dll!00007fff561dfa24()
vtkRenderingCore-9.1.dll!00007fff561d3aea()
vtkRenderingCore-9.1.dll!00007fff561d47e4()
vtkRenderingOpenGL2-9.1.dll!00007fff56daf06b()
Example-Drilling.exe!imstk::VTKViewer::updateModule() Line 226
	at D:\Work\iMSTK\Source\ViewerVTK\imstkVTKViewer.cpp(226)
Example-Drilling.exe!imstk::Module::update() Line 38
	at D:\Work\iMSTK\Source\Common\imstkModule.cpp(38)
Example-Drilling.exe!imstk::SimulationManager::start() Line 166
	at D:\Work\iMSTK\Source\SimulationManager\imstkSimulationManager.cpp(166)
Example-Drilling.exe!main() Line 424
	at D:\Work\iMSTK\Examples\Drilling\Drilling.cpp(424)
[Inline Frame] Example-Drilling.exe!invoke_main() Line 78
	at D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl(78)
Example-Drilling.exe!__scrt_common_main_seh() Line 288
	at D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl(288)
kernel32.dll!00007ff84a3c7034()
ntdll.dll!00007ff84c1c2651()

000000000795858d()
nvoglv64.dll!00007fff6f8bced6()
nvoglv64.dll!00007fff6fd5b66e()
nvoglv64.dll!00007fff6fd4fae8()
nvoglv64.dll!00007fff6fd494ab()
nvoglv64.dll!00007fff6f935e90()
nvoglv64.dll!00007fff6f753ac1()
nvoglv64.dll!00007fff6f923503()
nvoglv64.dll!00007fff6f923087()
nvoglv64.dll!00007fff6fb9bce8()
kernel32.dll!00007ff84a3c7034()
ntdll.dll!00007ff84c1c2651()

Random crashes can be related to data race maybe a buffer overflow, as i said we haven’t touch this part of functionality in a while especially since it’s using the old rigid body model.

While i can help you find the issue with some hints here there isn’t really a lot of time for me to try and reproduce this, i can have a look at the sources you can mail them to harald.scheirich@kitware.com, or you can just push something to a gist or gitlab snippet. A few things to check

  • Do you see the crashes when running the unmodified example
  • Do you see the crashes when runnign the example with just your model (no other changes)
  • Add #define IMSTK_CHECK_ARRAY_RANGE at the top in ImstkDataArray.h run and see if an index error gets caught
  • Run in the debugger sometimes that can show where issues are happening
  • Build a full imstk in Debug mode (it’s better to do this in a new build tree as you will have to rebuild all the dependecies as well) this will be slow to run but would catch buffer overwrites and other issues

from the answers to some of these questions we’d have to figure out where the issue lies