Skip to content

CellTreeLocator

Repository source: CellTreeLocator

Other languages

See (Cxx)

Question

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

Code

CellTreeLocator.py

#!/usr/bin/env python3

from vtkmodules.vtkCommonCore import reference
from vtkmodules.vtkCommonDataModel import (
    vtkCellTreeLocator,
    vtkGenericCell
)
from vtkmodules.vtkFiltersSources import vtkSphereSource


def main():
    sphere0 = vtkSphereSource(center=(0.0, 0.0, 0.0), radius=1.0)
    sphere0.update()

    # Create the cell locator tree.
    cell_tree = vtkCellTreeLocator(data_set=sphere0.output, automatic=True)
    cell_tree.BuildLocator()

    # These two points should not be on the sphere.
    test_inside = (0.5, 0.0, 0.0)
    test_outside = (10.0, 0.0, 0.0)

    passed = True
    pcoords = [0] * 3
    weights = [0] * 3
    tol = 0.0

    cell = vtkGenericCell()

    #  A point on the sphere.
    source_pt = [0.0] * 3
    sphere0.output.GetPoint(0, source_pt)
    cell_id = cell_tree.FindCell(source_pt, tol, cell, pcoords, weights)
    if cell_id >= 0:
        print(f'Point 0 on the sphere is in cell {cell_id}.')
        # Find the midpoint in the cell and check if it is in the same cell.
        bounds = cell.bounds
        mid_pt = list()
        for i in range(0, 6, 2):
            mid_pt.append(bounds[i] + (bounds[i + 1] - bounds[i]) / 2.0)
        cell_id_mid_pt = cell_tree.FindCell(mid_pt, tol, cell, pcoords, weights)
        if cell_id_mid_pt != cell_id:
            print('ERROR: The cell midpoint should be in the same cell.')
            passed = False
    else:
        print('ERROR: The cell corresponding to point 0 on the sphere was not found but should have been.')
        passed = False

    # Should be inside the sphere.
    cell_id = cell_tree.FindCell(test_inside, tol, cell, pcoords, weights)
    if cell_id >= 0:
        print(f'ERROR: test_inside point is in cell {cell_id} of the sphere but it should not be in the cell.')
        passed = False
    else:
        print('test_inside point is inside the sphere.')

    # Should be outside the sphere.
    cell_id = cell_tree.FindCell(test_outside, tol, cell, pcoords, weights)
    if cell_id >= 0:
        print(f'ERROR: test_outside point is in cell {cell_id} of the sphere but it should not be in the cell.')
        passed = False
    else:
        print('test_outside point is outside the sphere.')

    number_of_points = sphere0.output.number_of_points
    count_of_points = 0
    for i in range(0, number_of_points):
        source_pt = sphere0.output.GetPoint(i)
        cell_id = cell_tree.FindCell(source_pt, tol, cell, pcoords, weights)
        if cell_id:
            count_of_points += 1

    if count_of_points != number_of_points:
        num_missed = number_of_points - count_of_points
        print(f'ERROR: {num_missed} points should have been on the sphere!')
        passed = False
    else:
        print(f'Passed: A total of {count_of_points} points on the sphere were detected.')

    # This is based on [CellTreeLocator](https://gitlab.kitware.com/vtk/vtk/-/blob/master/Common/DataModel/Testing/Cxx/CellTreeLocator.cxx)
    # Kuhnan's sample code is used to test
    # vtkCellLocator::IntersectWithLine(...9 params...)

    # sphere1: The outer sphere.
    sphere1 = vtkSphereSource(theta_resolution=100, phi_resolution=100, radius=1.0)
    sphere1.update()

    # sphere2: The inner sphere.
    sphere2 = vtkSphereSource(theta_resolution=100, phi_resolution=100, radius=0.8)
    sphere2.update()

    # The normals obtained from the outer sphere.
    sphere_normals = sphere1.output.GetPointData().GetNormals()

    # Create the cell locator tree.
    locator = vtkCellTreeLocator(data_set=sphere2.output, automatic=True)
    locator.BuildLocator()

    # Initialise the counter and ray length.
    num_intersected = 0
    destin_pnt = [0] * 3
    tol = 0.0000001
    ray_len = 1.0 - 0.8 + tol  # = 1 - 0.8 + error tolerance
    param_t = reference(0.0)
    intersect = [0] * 3
    para_coord = [0] * 3
    sub_id = reference(0)
    cell_id = reference(0)

    # This loop traverses each point on the outer sphere (sphere1)
    #  and looks for an intersection on the inner sphere (sphere2).
    for i in range(0, sphere1.output.number_of_points):
        source_pnt = sphere1.output.GetPoint(i)
        normal_vec = sphere_normals.GetTuple(i)

        # Cast a ray in the negative direction toward sphere1.
        destin_pnt[0] = source_pnt[0] - ray_len * normal_vec[0]
        destin_pnt[1] = source_pnt[1] - ray_len * normal_vec[1]
        destin_pnt[2] = source_pnt[2] - ray_len * normal_vec[2]

        if locator.IntersectWithLine(source_pnt, destin_pnt, tol, param_t, intersect, para_coord, sub_id, cell_id,
                                     cell):
            num_intersected += 1

    if num_intersected != 9802:
        num_missed = 9802 - num_intersected
        print(f'ERROR: {num_missed} ray-sphere intersections missed!')
        passed = False
    else:
        print('Passed: A total of 9802 ray-sphere intersections detected.')

    if passed:
        print('All checks passed.')
    else:
        print('Some checks failed.')


if __name__ == '__main__':
    main()