如何使用vtk在Python中使用vtkOBBTree和IntersectWithLine查找线与PolyDataFilter的交点?

时间:2019-07-16 13:12:27

标签: python vtk raycasting

我有一个用vtkCylinderSource生成的定向圆柱,并对其进行了一些转换以获得我想要的定向。这是创建此定向圆柱的代码:

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

    # Create a cylinder.
    # Cylinder height vector is (0,1,0).
    # Cylinder center is in the middle of the cylinder
    cylinderSource = vtk.vtkCylinderSource()
    cylinderSource.SetRadius(radius)
    cylinderSource.SetResolution(50)

    # Generate a random start and end point
    # startPoint = [0] * 3
    # endPoint = [0] * 3

    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())

    cylinderSource.Update()

    # 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))
    actor.GetProperty().SetOpacity(opacity)
    return actor, transformPD

现在我想用这个定向圆柱体射线投射一条线。不幸的是,使用vtkCylinderSource作为vtkOBBTree的数据集会产生错误的结果。如何在PolyDataFilter中使用光线投射?

我想出了一个解决方案,其中将定向圆柱体导出到.stl文件中,然后再次读取该文件以使用IntersectWithLine实现射线投射算法。问题是我有成千上万个这样的定向圆柱体,这种方法(导出和读取)使我的代码非常慢。

def ray_cast(filename, p_source, p_target):
    '''

    :param filename: STL file to perform ray casting on.
    :param p_source: first point
    :param p_target: second point
    :return: code --> 0 : No intersection.
    :return: code --> +1 : p_source lies OUTSIDE the closed surface.
    :return; code --> -1 : p_source lies INSIDE closed surface

    '''

    reader = vtk.vtkSTLReader()
    reader.SetFileName(filename)
    reader.Update()
    mesh = reader.GetOutput()


    obbtree = vtk.vtkOBBTree()
    obbtree.SetDataSet(mesh)
    obbtree.BuildLocator()

    pointsVTKIntersection = vtk.vtkPoints()
    code = obbtree.IntersectWithLine(p_source, p_target, pointsVTKIntersection, None)
    # Extracting data
    pointsVTKIntersectionData = pointsVTKIntersection.GetData()
    noPointsVTKIntersection = pointsVTKIntersectionData.GetNumberOfTuples()
    pointsIntersection = []

    for idx in range(noPointsVTKIntersection):
        _tup = pointsVTKIntersectionData.GetTuple3(idx)
        pointsIntersection.append(_tup)

    return code, pointsIntersection, noPointsVTKIntersection

下图使用export-stl方法显示了所需的结果。 (绿色球是交点) Desired result

如果有任何建议和帮助,我将不胜感激。

1 个答案:

答案 0 :(得分:1)

使用vtkplotter

from vtkplotter import *

cyl = Cylinder() # vtkActor

cyl.alpha(0.5).pos(3,3,3).orientation([2,1,1])

p1, p2 = (0,0,0), (4,4,5)

ipts_coords = cyl.intersectWithLine(p1, p2)
print('hit coords are', ipts_coords)

pts = Points(ipts_coords, r=10).color("yellow")
# print(pts.polydata())  # is the vtkPolyData object

origin = Point()
ln = Line(p1,p2)

show(origin, cyl, ln, pts, axes=True)

enter image description here