shahriar
shahriar

Reputation: 362

Finding the intersection of two cylinders in 3D space using VTK in python

Using VTK in python i wrote some code to create an actor for objects that i want, e.g. for cylinder:

def cylinder_object(startPoint, endPoint, radius, my_color="DarkRed"):
    USER_MATRIX = True
    colors = vtk.vtkNamedColors()

    cylinderSource = vtk.vtkCylinderSource()
    cylinderSource.SetRadius(radius)
    cylinderSource.SetResolution(50)

    rng = vtk.vtkMinimalStandardRandomSequence()
    rng.SetSeed(8775070)  # For testing.8775070

    # Compute a basis
    normalizedX = [0] * 3
    normalizedY = [0] * 3
    normalizedZ = [0] * 3

    # The X axis is a vector from start to end
    vtk.vtkMath.Subtract(endPoint, startPoint, normalizedX)
    length = vtk.vtkMath.Norm(normalizedX)
    vtk.vtkMath.Normalize(normalizedX)

    # The Z axis is an arbitrary vector cross X
    arbitrary = [0] * 3
    for i in range(0, 3):
        rng.Next()
        arbitrary[i] = rng.GetRangeValue(-10, 10)
    vtk.vtkMath.Cross(normalizedX, arbitrary, normalizedZ)
    vtk.vtkMath.Normalize(normalizedZ)

    # The Y axis is Z cross X
    vtk.vtkMath.Cross(normalizedZ, normalizedX, normalizedY)
    matrix = vtk.vtkMatrix4x4()
    # Create the direction cosine matrix
    matrix.Identity()
    for i in range(0, 3):
        matrix.SetElement(i, 0, normalizedX[i])
        matrix.SetElement(i, 1, normalizedY[i])
        matrix.SetElement(i, 2, normalizedZ[i])
    # Apply the transforms
    transform = vtk.vtkTransform()
    transform.Translate(startPoint)  # translate to starting point
    transform.Concatenate(matrix)  # apply direction cosines
    transform.RotateZ(-90.0)  # align cylinder to x axis
    transform.Scale(1.0, length, 1.0)  # scale along the height vector
    transform.Translate(0, .5, 0)  # translate to start of cylinder

    # Transform the polydata
    transformPD = vtk.vtkTransformPolyDataFilter()
    transformPD.SetTransform(transform)
    transformPD.SetInputConnection(cylinderSource.GetOutputPort())

    # Create a mapper and actor for the arrow
    mapper = vtk.vtkPolyDataMapper()
    actor = vtk.vtkActor()
    if USER_MATRIX:
        mapper.SetInputConnection(cylinderSource.GetOutputPort())
        actor.SetUserMatrix(transform.GetMatrix())
    else:
        mapper.SetInputConnection(transformPD.GetOutputPort())
    actor.SetMapper(mapper)
    actor.GetProperty().SetColor(colors.GetColor3d(my_color))
    return actor

This function returns an actor where i can render it later using vtkRender. Now what i want is to first find whether two given cylinder Actors are intersected or not and second find the intersection points. Could i use the vtkTriangleFilter on my cylinder and use the vtkOBBTree and ray casting to find whether the intersection happens or not?

Here are two oriented cylinders that are intersected: Intersected Cylinders

Upvotes: 3

Views: 2230

Answers (1)

L.C.
L.C.

Reputation: 1145

First, you'll need to work on the vtkPolyData object (i.e. the geometry), not on the vtkActor. You'll probably need to use vtkTransformPolyDataFilter output as your vtkPolyData (as you did in the else statement - example here) rather than calling setUserMatrix.

You can use vtkBooleanOperationPolyDataFilter: an example can be found here (in C++, but I'm sure it can help) and here (in Python). If the resulting geometry is not empty, then the cylinders intersect.

If it does not fit your needs, you can convert the cylinders from polydata to imagedata (image volume, voxels) using vtkImplicitModeller; then computing the intersection volume is easier and more accurate (you can use vtkImageLogic). You can also convert the intersection back to vtkPolyData using vtkFlyingEdges3D (a fast version of vtkMarchingCubes).

Edit: as disussed in the comments, because there are many cylinders execution time is a matter. You could try to optimize the process by computing the distance between the axis of each pair of cylinders to detect IF they intersect and in case they do, compute the intersection as described in the first part of this answer. My idea is the following: compute the shortest distance between the segments (one method is described here, there's also the c++ code for segment-to-segment distance, that's what you need). Compare the distance with the sum of the radius of the two cylinders and if it's shorter, compute the intersection.

Upvotes: 1

Related Questions