Vtk point cloud display multiple points (cluster)

Cannot visualize the points around one of the selected points in point cloud. Not sure what I am missing. I used the below code. What it does is just takes a pointcloud and convert it into polydata and visualize it. After visualizing the pointcloud, I use mouse to select one point and calculate points around that particular point in a given radius. I am able to calculate those points but not able to visualize those. Also moving further I select 1000 random points in data and calculate their clusters too, calculate Hausdorff distances of each with original cluster and visualize the minimum distance cluster. In all this I am not able to visualize any cluster.

import vtk
import numpy as np
import open3d as o3d
import math
from numpy import random
from scipy.spatial.distance import directed_hausdorff

import vtkmodules.vtkRenderingOpenGL2
from vtkmodules.vtkCommonColor import vtkNamedColors
from vtkmodules.vtkCommonCore import vtkIdTypeArray
from vtkmodules.vtkCommonDataModel import (
    vtkSelection,
    vtkSelectionNode,
    vtkUnstructuredGrid
)
from vtkmodules.vtkFiltersCore import vtkTriangleFilter
from vtkmodules.vtkFiltersExtraction import vtkExtractSelection
from vtkmodules.vtkFiltersSources import vtkPlaneSource
from vtkmodules.vtkInteractionStyle import vtkInteractorStyleTrackballCamera
from vtkmodules.vtkRenderingCore import (
    vtkActor,
    vtkCellPicker,
    vtkDataSetMapper,
    vtkPolyDataMapper,
    vtkRenderWindow,
    vtkRenderWindowInteractor,
    vtkRenderer
)



class VtkPointCloud:

    def __init__(self, zMin=-10.0, zMax=10.0, maxNumPoints=2e6):
        # c = vtkNamedColors()
        self.maxNumPoints = maxNumPoints
        self.vtkPolyData = vtk.vtkPolyData()
        self.clearPoints()
        mapper = vtk.vtkPolyDataMapper()
        mapper.SetInputData(self.vtkPolyData)
        mapper.SetColorModeToDefault()
        mapper.SetScalarRange(zMin, zMax)
        mapper.SetScalarVisibility(1)
        self.vtkActor = vtk.vtkActor()
        # self.vtkActor.GetProperty().SetColor(1,1,1)
        # self.vtkActor.GetProperty().SetColor(c.GetColor3d('Yellow'))
        self.vtkActor.SetMapper(mapper)

    def addPoint(self, point):
        if self.vtkPoints.GetNumberOfPoints() < self.maxNumPoints:
            pointId = self.vtkPoints.InsertNextPoint(point[:])
            self.vtkDepth.InsertNextValue(point[2])
            self.vtkCells.InsertNextCell(1)
            self.vtkCells.InsertCellPoint(pointId)
        else:
            r = random.randint(0, self.maxNumPoints)
            self.vtkPoints.SetPoint(r, point[:])
        self.vtkCells.Modified()
        self.vtkPoints.Modified()
        self.vtkDepth.Modified()

    def clearPoints(self):
        self.vtkPoints = vtk.vtkPoints()
        self.vtkCells = vtk.vtkCellArray()
        self.vtkDepth = vtk.vtkDoubleArray()
        self.vtkDepth.SetName('DepthArray')
        self.vtkPolyData.SetPoints(self.vtkPoints)
        self.vtkPolyData.SetVerts(self.vtkCells)
        self.vtkPolyData.GetPointData().SetScalars(self.vtkDepth)
        self.vtkPolyData.GetPointData().SetActiveScalars('DepthArray')

# Catch mouse events
class MouseInteractorStyle(vtkInteractorStyleTrackballCamera):
    def __init__(self, data):
        self.AddObserver('LeftButtonPressEvent', self.left_button_press_event)
        self.AddObserver('RightButtonPressEvent', self.right_button_press_event)
        self.data = data
        self.selected_mapper = vtkDataSetMapper()
        self.selected_actor = vtkActor()

        self.selected_mapper2 = vtkDataSetMapper()
        self.selected_actor2 = vtkActor()

        self.vtk_list = vtk.vtkIdList()
        self.locator = vtk.vtkPointLocator()
        self.locator.SetDataSet(self.data)
        self.locator.BuildLocator()

        self.colors = vtkNamedColors()
    def left_button_press_event(self, obj, event):
                

        pos = self.GetInteractor().GetEventPosition()

        picker = vtkCellPicker()
        picker.SetTolerance(0.001)

        # Pick from this location.
        picker.Pick(pos[0], pos[1], 0, self.GetDefaultRenderer())

        world_position = picker.GetPickPosition()
        print(f'Cell id is: {picker.GetCellId()}')
        
        # print(world_position)

        self.locator.FindPointsWithinRadius(0.02,world_position, self.vtk_list)
        print(self.vtk_list)

        if picker.GetCellId() != -1:
            print(f'Pick position is: ({world_position[0]:.6g}, {world_position[1]:.6g}, {world_position[2]:.6g})')

            ids = vtkIdTypeArray()
            ids.SetNumberOfComponents(1)
            ids.InsertNextValue(picker.GetCellId())
            # print(ids,'\n')

            selection_node = vtkSelectionNode()
            selection_node.SetFieldType(vtkSelectionNode.CELL)
            selection_node.SetContentType(vtkSelectionNode.INDICES)
            selection_node.SetSelectionList(ids)

            selection = vtkSelection()
            selection.AddNode(selection_node)

            extract_selection = vtkExtractSelection()
            extract_selection.SetInputData(0, self.data)
            extract_selection.SetInputData(1, selection)
            extract_selection.Update()

            # In selection
            selected = vtkUnstructuredGrid()
            selected.ShallowCopy(extract_selection.GetOutput())

            print(f'Number of points in the selection: {selected.GetNumberOfPoints()}')
            # print(f'Number of cells in the selection : {selected.GetNumberOfCells()}\n')

            print('########################\n') 

            self.selected_mapper.SetInputData(selected)
            self.selected_actor.SetMapper(self.selected_mapper)
            # self.selected_actor.GetProperty().EdgeVisibilityOn()
            self.selected_actor.GetProperty().SetColor(self.colors.GetColor3d('Black'))
            self.selected_actor.GetProperty().SetPointSize(10)
            self.selected_actor.GetProperty().SetLineWidth(3)
            # print(self.selected_actor)

            self.GetInteractor().GetRenderWindow().GetRenderers().GetFirstRenderer().AddActor(self.selected_actor)
            

        # Forward events
        self.OnLeftButtonDown()

    def right_button_press_event(self, obj, event):
    
        if self.vtk_list.GetNumberOfIds() == 0:
            return
        else:
            ids2 = vtkIdTypeArray()
            ids2.SetNumberOfComponents(1)
            for i in range(self.vtk_list.GetNumberOfIds()):
                # print(i)
                ids2.InsertNextValue(i)
            # print(ids2)
            selection_node2 = vtkSelectionNode()
            selection_node2.SetFieldType(vtkSelectionNode.CELL)
            selection_node2.SetContentType(vtkSelectionNode.INDICES)
            selection_node2.SetSelectionList(ids2)

            selection2 = vtkSelection()
            selection2.AddNode(selection_node2)

            extract_selection2 = vtkExtractSelection()
            extract_selection2.SetInputData(0, self.data)
            extract_selection2.SetInputData(1, selection2)
            extract_selection2.Update()
            

    #         # In selection
    
            selected2 = vtkUnstructuredGrid()
            selected2.ShallowCopy(extract_selection2.GetOutput())

            print(f'Number of neighboring points: {selected2.GetNumberOfPoints()}')
    #         # print(f'Number of neighboring cells: {selected2.GetNumberOfCells()}\n')
            print('########################\n') 


            self.selected_mapper2.SetInputData(selected2)
            self.selected_actor2.SetMapper(self.selected_mapper2)
            # self.selected_actor.GetProperty().EdgeVisibilityOn()
            self.selected_actor2.GetProperty().SetColor(self.colors.GetColor3d("tan"))
            self.selected_actor2.GetProperty().SetPointSize(10)
            self.selected_actor2.GetProperty().SetLineWidth(3)
            # print(self.selected_actor2)

            self.GetInteractor().GetRenderWindow().GetRenderers().GetFirstRenderer().AddActor(self.selected_actor2)

            print('Randomly Selecting 1000 points in the data........')
            point_indices = []
            cluster_points = np.zeros((self.vtk_list.GetNumberOfIds(),3))
            # print(cluster_points)
            print('Calculating the clusters around the centers ......')
            for i in range(self.vtk_list.GetNumberOfIds()):
            
                point_indices.append(self.vtk_list.GetId(i))
            
                cluster_points[i]=pointCloud.vtkPolyData.GetPoint(self.vtk_list.GetId(i))
            
            point_indices = np.asarray(point_indices)

            new_points= np.delete(points,point_indices, axis=0)

            random_array = np.random.randint(0,new_points.shape[0],(1000))
            
            min_haus = 1000000000.0
            for i in range(random_array.shape[0]):
                new_list=vtk.vtkIdList()
                new_center = new_points[random_array[i]]
            #     print('new center to find cluster:',new_center)
                self.locator.FindPointsWithinRadius(0.02,new_center, new_list)
                new_cluster_points = np.zeros((new_list.GetNumberOfIds(),3))
                for x in range(new_list.GetNumberOfIds()):
                    new_cluster_points[x]=pointCloud.vtkPolyData.GetPoint(new_list.GetId(x))
                    haus = directed_hausdorff(cluster_points,new_cluster_points)[0]
                    if haus<min_haus:
                        min_haus = haus
                        idx = random_array[i]
                        min_center = new_points[random_array[i]]

                # print('haus:',haus)
            print('min haus:',min_haus)
            print('idx of min haus:',idx)
            print('center of the min haus cluster:',min_center)

            min_list = vtk.vtkIdList()
            self.locator.FindPointsWithinRadius(0.02,min_center, min_list)
            print('Min list for min center', min_list)
    
    #     # Forward events
        self.OnRightButtonDown()

# Initialize point clouds
pointCloud = VtkPointCloud()

pointCloud2 = VtkPointCloud()
# print(type(pointCloud))

# Loading Point cloud using open3d
pt_cloud = o3d.io.read_point_cloud('fused_cloud_normal.ply')
points = np.asarray(pt_cloud.points)

pt_cloud2 = o3d.io.read_point_cloud('all_projected_pts.ply')
points2 = np.asarray(pt_cloud2.points)


# Adding the points into polydata
for row in points:
    pointCloud.addPoint(row)


for row in points2:
    pointCloud2.addPoint(row)


# Intialize actor
c = vtkNamedColors()
actor = pointCloud.vtkActor
actor.GetProperty().SetPointSize(10)
actor.GetProperty().SetColor(c.GetColor3d('Yellow'))

# actor.GetProperty().SetColor(0,0,0)
# Renderer
renderer = vtk.vtkRenderer()
renderer.AddActor(actor)
# renderer.AddActor(pointCloud2.vtkActor)
renderer.SetBackground(.1, .1, .4)
renderer.ResetCamera()

# Render Window
renderWindow = vtk.vtkRenderWindow()
renderWindow.AddRenderer(renderer)

style = MouseInteractorStyle(pointCloud.vtkPolyData)
style.SetDefaultRenderer(renderer)

# Interactor
renderWindowInteractor = vtk.vtkRenderWindowInteractor()
renderWindowInteractor.SetRenderWindow(renderWindow)
renderWindowInteractor.SetInteractorStyle(style)


# Begin Interaction
renderWindow.Render()
renderWindowInteractor.Start()

the picker doesn’t seem to pick anything though… maybe using vtkPropPicker (?), this is the way i would do it in vedo, in case you’re interested:

import numpy as np
from vedo import Points, Text2D, Plotter

def func(evt):
    if not evt.actor:
        return
    pt = evt.picked3d
    ids = evt.actor.closest_point(pt, radius=1.0, return_point_id=True)
    selpts = Points(points1[ids]).pickable(False).c("red5").ps(12)
    selpts.name = "nearpoints"
    d = selpts.hausdorff_distance(vpoints2)
    txt.text(f"n = {len(ids)}, d = {d}")
    plt.remove("nearpoints").add(selpts)

# vpoints1 = Points("fused_cloud_normal.ply").ps(10)
# points1 = vpoints1.points()
points1  = np.random.randn(1000,3) + [0,0,0]
points2  = np.random.randn(1000,3) + [7,0,0]
vpoints1 = Points(points1).ps(10)
vpoints2 = Points(points2).ps(10).pickable(False).c("blue2")
txt = Text2D("Hover mouse", font="Calco")

plt = Plotter()
plt.add_callback("hover", func)
plt.show(vpoints1, vpoints2, txt, axes=1).close()

I made it work in some way. There was a bug in line,
ids2.InsertNextValue(i)
It should be,
ids2.InsertNextValue(self.vtk_list.GetId(i)).
Looks like it was visualizing but colors were not helpful.

It is still not perfect as I am not able to change the colors of points according to selection or cluster but this is a small problem which I am planning to solve later.