Skip to content

CollisionDetection

vtk-examples/Python/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.

  1. All contacts (0) finds all the contacting cell pairs with two points per collision.
  2. First contact (1) quickly find the first contact point.
  3. 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 (Cxx)

Question

If you have a question about this example, please use the VTK Discourse Forum

Code

CollisionDetection.py

#!/usr/bin/env python

import time

# noinspection PyUnresolvedReferences
import vtkmodules.vtkInteractionStyle
# noinspection PyUnresolvedReferences
import vtkmodules.vtkRenderingFreeType
# noinspection PyUnresolvedReferences
import vtkmodules.vtkRenderingOpenGL2
from vtkmodules.vtkCommonColor import vtkNamedColors
from vtkmodules.vtkCommonMath import vtkMatrix4x4
from vtkmodules.vtkCommonTransforms import vtkTransform
from vtkmodules.vtkFiltersModeling import vtkCollisionDetectionFilter
from vtkmodules.vtkFiltersSources import vtkSphereSource
from vtkmodules.vtkRenderingCore import (
    vtkActor,
    vtkPolyDataMapper,
    vtkRenderWindow,
    vtkRenderWindowInteractor,
    vtkRenderer,
    vtkTextActor
)


def get_program_parameters():
    import argparse
    description = 'Collision detection.'
    epilogue = '''
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.

1. All contacts (0) finds all the contacting cell pairs with two points per collision.
2. First contact (1) quickly find the first contact point.
3. Half contacts (2) finds all the contacting cell pairs with one points per collision.

    '''
    parser = argparse.ArgumentParser(description=description, epilog=epilogue,
                                     formatter_class=argparse.RawDescriptionHelpFormatter)
    parser.add_argument('contactMode', nargs='?', default=0, type=int, help='Contact mode 0 (default), 1, or 2.')
    args = parser.parse_args()
    return args.contactMode


def main():
    contactMode = get_program_parameters()

    # Define colors
    colors = vtkNamedColors()

    sphere0 = vtkSphereSource()
    sphere0.SetRadius(0.29)
    sphere0.SetPhiResolution(31)
    sphere0.SetThetaResolution(31)
    sphere0.SetCenter(0.0, 0, 0)

    sphere1 = vtkSphereSource()
    sphere1.SetPhiResolution(30)
    sphere1.SetThetaResolution(30)
    sphere1.SetRadius(0.3)

    matrix1 = vtkMatrix4x4()
    transform0 = vtkTransform()

    collide = vtkCollisionDetectionFilter()
    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()
    elif contactMode == 1:
        collide.SetCollisionModeToFirstContact()
    else:
        collide.SetCollisionModeToHalfContacts()
    collide.GenerateScalarsOn()

    # Visualize
    mapper1 = vtkPolyDataMapper()
    mapper1.SetInputConnection(collide.GetOutputPort(0))
    mapper1.ScalarVisibilityOff()
    actor1 = vtkActor()
    actor1.SetMapper(mapper1)
    actor1.GetProperty().BackfaceCullingOn()
    actor1.SetUserTransform(transform0)
    actor1.GetProperty().SetDiffuseColor(colors.GetColor3d("Tomato"))
    actor1.GetProperty().SetRepresentationToWireframe()

    mapper2 = vtkPolyDataMapper()
    mapper2.SetInputConnection(collide.GetOutputPort(1))

    actor2 = vtkActor()
    actor2.SetMapper(mapper2)
    actor2.GetProperty().BackfaceCullingOn()
    actor2.SetUserMatrix(matrix1)

    mapper3 = vtkPolyDataMapper()
    mapper3.SetInputConnection(collide.GetContactsOutputPort())
    mapper3.SetResolveCoincidentTopologyToPolygonOffset()

    actor3 = vtkActor()
    actor3.SetMapper(mapper3)
    actor3.GetProperty().SetColor(colors.GetColor3d("Black"))
    actor3.GetProperty().SetLineWidth(3.0)

    txt = vtkTextActor()
    txt.GetTextProperty().SetFontSize(18)

    renderer = vtkRenderer()
    renderer.UseHiddenLineRemovalOn()
    renderer.AddActor(actor1)
    renderer.AddActor(actor2)
    renderer.AddActor(actor3)
    renderer.AddActor(txt)
    renderer.SetBackground(colors.GetColor3d("Gray"))
    renderer.UseHiddenLineRemovalOn()

    renderWindow = vtkRenderWindow()
    renderWindow.SetSize(640, 480)
    renderWindow.AddRenderer(renderer)

    interactor = vtkRenderWindowInteractor()
    interactor.SetRenderWindow(renderWindow)

    # Move the first object
    numSteps = 100
    dx = 1.0 / float(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 i in range(0, numSteps):
        transform0.Translate(dx, 0.0, 0.0)
        renderer.ResetCameraClippingRange()
        s = '{:s}: Number of contact cells is {:d}'.format(collide.GetCollisionModeAsString(),
                                                           collide.GetNumberOfContacts())
        txt.SetInput(s)
        renderWindow.Render()
        if collide.GetNumberOfContacts() > 0:
            break
        # The total animation time is 3 seconds
        time.sleep(3.0 / numSteps)

    renderer.ResetCamera()
    renderWindow.Render()
    renderWindow.Render()
    interactor.Start()
    # In Field Data there will be an array named "ContactCells".
    # This array indexes contacting cells (e.g.) index 10 of array 0
    #  points to a cell (triangle) which contacts/intersects a cell
    #  at index 10 of array 1.
    # You can directly obtain these, see GetContactCells(int i)
    #  in the documentation.
    # print(collide.GetOutput(0))
    # print(collide.GetOutput(1))


if __name__ == '__main__':
    main()