CollisionDetection
VTKEx/Cxx/Visualization/CollisionDetection
Description¶
This examples uses vtkCollisionDetectionFilter to find the intersection between a fixed (solid white) and moving (red wireframe) sphere. The animation places the moving sphere some distance from the fixed sphere and moves the moving sphere until it contacts the fixed sphere.
Three collision modes are available and can be set as the first argument on the command line.
- All contacts (0) finds all the contacting cell pairs with two points per collision.
- First contact (1) quickly find the first contact point.
- Half contacts (2) finds all the contacting cell pairs with one points per collision.
The animation pauses between each frame. The total animation should be 3 seconds.
Three videos on the VTK Examples Project youtube playlist show each of the collision modes.
Other languages
See (Python)
Question
If you have a simple question about this example contact us at VTKExProject If your question is more complex and may require extended discussion, please use the VTK Discourse Forum
Code¶
CollisionDetection.cxx
#include "vtkActor.h"
#include "vtkCamera.h"
#include "vtkCollisionDetectionFilter.h"
#include "vtkMatrix4x4.h"
#include "vtkNamedColors.h"
#include "vtkPolyDataMapper.h"
#include "vtkProperty.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkRenderer.h"
#include "vtkSmartPointer.h"
#include "vtkSphereSource.h"
#include "vtkTextActor.h"
#include "vtkTextProperty.h"
#include "vtkTransform.h"
#include <chrono>
#include <sstream>
#include <string>
#include <thread>
int main(int argc, char* argv[])
{
int contactMode = 0;
if (argc > 1)
{
contactMode = std::stoi(std::string(argv[1]));
}
auto sphere0 = vtkSmartPointer<vtkSphereSource>::New();
sphere0->SetRadius(.29);
sphere0->SetPhiResolution(31);
sphere0->SetThetaResolution(31);
sphere0->SetCenter(0.0, 0, 0);
auto sphere1 = vtkSmartPointer<vtkSphereSource>::New();
sphere1->SetPhiResolution(30);
sphere1->SetThetaResolution(30);
sphere1->SetRadius(0.3);
auto matrix1 = vtkSmartPointer<vtkMatrix4x4>::New();
auto transform0 = vtkSmartPointer<vtkTransform>::New();
auto collide = vtkSmartPointer<vtkCollisionDetectionFilter>::New();
collide->SetInputConnection(0, sphere0->GetOutputPort());
collide->SetTransform(0, transform0);
collide->SetInputConnection(1, sphere1->GetOutputPort());
collide->SetMatrix(1, matrix1);
collide->SetBoxTolerance(0.0);
collide->SetCellTolerance(0.0);
collide->SetNumberOfCellsPerNode(2);
if (contactMode == 0)
{
collide->SetCollisionModeToAllContacts();
}
else if (contactMode == 1)
{
collide->SetCollisionModeToFirstContact();
}
else
{
collide->SetCollisionModeToHalfContacts();
}
collide->GenerateScalarsOn();
// Visualize
auto colors = vtkSmartPointer<vtkNamedColors>::New();
auto mapper1 = vtkSmartPointer<vtkPolyDataMapper>::New();
mapper1->SetInputConnection(collide->GetOutputPort(0));
mapper1->ScalarVisibilityOff();
auto actor1 = vtkSmartPointer<vtkActor>::New();
actor1->SetMapper(mapper1);
actor1->GetProperty()->BackfaceCullingOn();
actor1->SetUserTransform(transform0);
actor1->GetProperty()->SetDiffuseColor(
colors->GetColor3d("Tomato").GetData());
actor1->GetProperty()->SetRepresentationToWireframe();
auto mapper2 = vtkSmartPointer<vtkPolyDataMapper>::New();
mapper2->SetInputConnection(collide->GetOutputPort(1));
auto actor2 = vtkSmartPointer<vtkActor>::New();
actor2->SetMapper(mapper2);
actor2->GetProperty()->BackfaceCullingOn();
actor2->SetUserMatrix(matrix1);
auto mapper3 = vtkSmartPointer<vtkPolyDataMapper>::New();
mapper3->SetInputConnection(collide->GetContactsOutputPort());
mapper3->SetResolveCoincidentTopologyToPolygonOffset();
auto actor3 = vtkSmartPointer<vtkActor>::New();
actor3->SetMapper(mapper3);
actor3->GetProperty()->SetColor(colors->GetColor3d("Black").GetData());
actor3->GetProperty()->SetLineWidth(3.0);
auto txt = vtkSmartPointer<vtkTextActor>::New();
txt->GetTextProperty()->SetFontSize(18);
auto renderer = vtkSmartPointer<vtkRenderer>::New();
renderer->UseHiddenLineRemovalOn();
renderer->AddActor(actor1);
renderer->AddActor(actor2);
renderer->AddActor(actor3);
renderer->AddActor(txt);
renderer->SetBackground(colors->GetColor3d("Gray").GetData());
renderer->UseHiddenLineRemovalOn();
auto renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->SetSize(640, 480);
renderWindow->AddRenderer(renderer);
auto interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
interactor->SetRenderWindow(renderWindow);
// Move the first object
int numSteps = 100;
double dx = 1.0 / static_cast<double>(numSteps) * 2.0;
transform0->Translate(-numSteps * dx - .3, 0.0, 0.0);
renderWindow->Render();
renderer->GetActiveCamera()->Azimuth(-60);
renderer->GetActiveCamera()->Elevation(45);
renderer->GetActiveCamera()->Dolly(1.2);
renderWindow->SetWindowName("CollisionDetection");
renderWindow->Render();
for (int i = 0; i < numSteps; ++i)
{
transform0->Translate(dx, 0.0, 0.0);
renderer->ResetCameraClippingRange();
std::ostringstream textStream;
textStream << collide->GetCollisionModeAsString()
<< ": Number of contact cells is "
<< collide->GetNumberOfContacts();
txt->SetInput(textStream.str().c_str());
renderWindow->Render();
if (collide->GetNumberOfContacts() > 0)
{
break;
}
// The total animation time is 3 seconds
std::this_thread::sleep_for(std::chrono::milliseconds(3000 / numSteps));
}
renderer->ResetCamera();
renderWindow->Render();
interactor->Start();
// In Field Data there will be an array named "ContactCells".
// This array indexes contacting cells (e.g.) index 50 of array 0
// points to a cell (triangle) which contacts/intersects a cell
// at index 50 of array 1.
// You can directly obtain these, see GetContactCells(int i)
// in the documentation.
// collide->GetOutput(0)->Print(std::cout);
//collide->GetOutput(1)->Print(std::cout);
return EXIT_SUCCESS;
}
CMakeLists.txt¶
cmake_minimum_required(VERSION 3.3 FATAL_ERROR)
project(CollisionDetection)
find_package(VTK COMPONENTS
vtkvtkCommonColor
vtkvtkCommonCore
vtkvtkCommonMath
vtkvtkCommonTransforms
vtkvtkFiltersModeling
vtkvtkFiltersSources
vtkvtkInteractionStyle
vtkvtkRenderingContextOpenGL2
vtkvtkRenderingCore
vtkvtkRenderingFreeType
vtkvtkRenderingGL2PSOpenGL2
vtkvtkRenderingOpenGL2 QUIET)
if (NOT VTK_FOUND)
message("Skipping CollisionDetection: ${VTK_NOT_FOUND_MESSAGE}")
return ()
endif()
message (STATUS "VTK_VERSION: ${VTK_VERSION}")
if (VTK_VERSION VERSION_LESS "8.90.0")
# old system
include(${VTK_USE_FILE})
add_executable(CollisionDetection MACOSX_BUNDLE CollisionDetection.cxx )
target_link_libraries(CollisionDetection PRIVATE ${VTK_LIBRARIES})
else ()
# include all components
add_executable(CollisionDetection MACOSX_BUNDLE CollisionDetection.cxx )
target_link_libraries(CollisionDetection PRIVATE ${VTK_LIBRARIES})
# vtk_module_autoinit is needed
vtk_module_autoinit(
TARGETS CollisionDetection
MODULES ${VTK_LIBRARIES}
)
endif ()
Download and Build CollisionDetection¶
Click here to download CollisionDetection and its CMakeLists.txt file. Once the tarball CollisionDetection.tar has been downloaded and extracted,
cd CollisionDetection/build
If VTK is installed:
cmake ..
If VTK is not installed but compiled on your system, you will need to specify the path to your VTK build:
cmake -DVTK_DIR:PATH=/home/me/vtk_build ..
Build the project:
make
and run it:
./CollisionDetection
WINDOWS USERS
Be sure to add the VTK bin directory to your path. This will resolve the VTK dll's at run time.