TimerCallBack and MouseCallBack

Hello all,
I am working on TImerCallback and MouseCallback.
In my MouseCallback I choose a point(seedPoint) with mouse click in a glyph3D field. It creates a sphere in the seedPoint.
Now the glyphfields has vectors and I want the TimerCallback to create spheres iteratively based on the nearest point(with stepsize s) towards the vector direction of the next point.
There should be 1000 iterations.
The idea is based on brain tractography. Please see the seedpoints below with point locations in the terminal. Outside the brain location gives point id as -1.

I am using the following codes for MouseCallback:

class MyMouseCallback : public vtkInteractorStyleTrackballCamera
{
public:
	MyMouseCallback() {}
	~MyMouseCallback() {}

	static MyMouseCallback* New()
	{
		MyMouseCallback* callback = new MyMouseCallback();
		return callback;
	}
	virtual void OnLeftButtonDown() override
	{
		// do something customized here

		// figure out where the mouse is (pixel x, y)
		// we have the interactor from our parent class
		int x, y;
		this->Interactor->GetEventPosition(x, y); //creates pixel location object this
		std::cout << "Picked pixel: " << x << " " << y << std::endl;

		// figure out where that maps to in the scene (which point of which mesh?)
		// we need to know the picker and renderer
		vtkSmartPointer < vtkPointPicker > picker = dynamic_cast < vtkPointPicker *> ( this->Interactor->GetPicker() ) ;
		//vtkSmartPointer < vtkCellPicker > picker = dynamic_cast <vtkCellPicker*> (this->Interactor->GetPicker());

		vtkSmartPointer < vtkRenderWindow > window = this->Interactor->GetRenderWindow();
		vtkSmartPointer < vtkRenderer > renderer = window->GetRenderers()->GetFirstRenderer();
		renderer->GetActors()->InitTraversal(); //NS
		picker->Pick(x, y, 0, renderer);

		std::cout << "Picked point id: " << picker->GetPointId() << std::endl ;

		// we need to figure out where the mesh is
		vtkSmartPointer < vtkPolyDataMapper > mapper = dynamic_cast <vtkPolyDataMapper*> (picker->GetMapper());
		if (mapper != NULL)
		{	
			
			vtkIdType seedPointID = picker->GetPointId();
			double* pos = picker->GetPickPosition(); //getting the world coordinate position
			std::cout << "Pick position (world coordinates) is: " << pos[0] << " " << pos[1] << " " << pos[2] << std::endl;
			
			vtkSmartPointer<vtkSphereSource> seedSphere = vtkSmartPointer<vtkSphereSource>::New();
			//seedSphere->SetCenter(pos[0], pos[1], pos[2]);
			seedSphere->SetCenter(pos);
			seedSphere->SetRadius(1.0);
			seedSphere->Update(); //NS
			//Create a mapper and actor
			vtkSmartPointer<vtkPolyDataMapper> sphereMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
			sphereMapper->SetInputConnection(seedSphere->GetOutputPort());
			vtkSmartPointer<vtkActor> sphereActor = vtkSmartPointer<vtkActor>::New();
			sphereActor->SetMapper(sphereMapper);
			//std::cout << "Randoms: " << rgb[0] << " " << rgb[1] << " " << rgb[2] << std::endl;
			
			float rgb[3];
			rgb[0] = vtkMath::Random(0, 1);
			rgb[1] = vtkMath::Random(0, 1);
			rgb[2] = vtkMath::Random(0, 1);
			sphereActor->GetProperty()->SetColor(rgb[0], rgb[1], rgb[2]);

			renderer->AddActor(sphereActor);

			//for tract:
			/*vtkSmartPointer<vtkPoints> tractPoints = vtkSmartPointer<vtkPoints>::New();
			tractPoints->InsertNextPoint(pos);
			//creating polylines
			vtkSmartPointer <vtkPolyLine> tract = vtkSmartPointer <vtkPolyLine>::New();
			vtkIdType numOfTractPoints = tractPoints->GetNumberOfPoints();
			tract->GetPointIds()->SetNumberOfIds(numOfTractPoints);
			for (unsigned int i = 0; i < numOfTractPoints; i++)
			{
				tract->GetPointIds()->SetId(i, i);
			}
			vtkSmartPointer <vtkCellArray> tractCells = vtkSmartPointer <vtkCellArray>::New();
			tractCells->InsertNextCell(tract);

			vtkSmartPointer <vtkPolyData> polyData = vtkSmartPointer <vtkPolyData>::New();
			polyData->SetPoints(tractPoints);
			polyData->SetLines(tractCells);
			// Setup the mapper and actor for the polydata
			vtkSmartPointer <vtkPolyDataMapper> tractMapper = vtkSmartPointer <vtkPolyDataMapper>::New();
			tractMapper->SetInputData(polyData);
			vtkSmartPointer <vtkActor> tractActor = vtkSmartPointer <vtkActor>::New();
			tractActor->SetMapper(tractMapper);
			tractActor->GetProperty()->SetColor(rgb[0],rgb[1],rgb[2]); // set the color of tract to blue
			// Add this actor to the actor collection of the renderer
			renderer->AddActor(tractActor);*/
			//for tract
			
			vtkSmartPointer < vtkPolyData > mesh = mapper->GetInput();
			
			// "update"
			mesh->Modified(); //if you do not update, doesn't do anything
		}
		// now go back to doing nromal left button things
		vtkInteractorStyleTrackballCamera::OnLeftButtonDown();
	}
	void setStepSize(double stepSize)
	{
		this->s = stepSize;
	}

private:
	double s; // step size for the tract growth  
};


class TimerCallback : public vtkCommand
{
public:
	TimerCallback() {}
	~TimerCallback() {}
	static TimerCallback* New()
	{
		TimerCallback* callback = new TimerCallback();
		return callback;
	}
	virtual void Execute(vtkObject* caller, unsigned long eventId, void* callData)
	{
		vtkSmartPointer < vtkRenderWindowInteractor > interactor = static_cast <vtkRenderWindowInteractor*> (caller);
		vtkRenderWindow* renderWindow = interactor->GetRenderWindow();
		vtkRenderer* renderer = renderWindow->GetRenderers()->GetFirstRenderer();
			this->actor->RotateZ(rotAmount);

			// change mesh
			vtkPolyDataMapper* mapper = dynamic_cast <vtkPolyDataMapper*> (this->actor->GetMapper());
			vtkPolyData* mesh = dynamic_cast <vtkPolyData*> (mapper->GetInput());

			int nPts = mesh->GetNumberOfPoints();
			for (unsigned int i = 0; i < 10; i++)
			{
				double pointCoordinates[3];
				mesh->GetPoint(i, pointCoordinates);
				pointCoordinates[0] += 1;
				mesh->GetPoints()->SetPoint(i, pointCoordinates);
			}
			mesh->Modified();
	}

	void SetActor(vtkActor* ac, int degrees)
	{
		this->actor = ac; 
		this->rotAmount = degrees;
	}
private:
	vtkActor* actor;
	int rotAmount;
};

The rotate codes are from another example where an object is rotated 5 degrees.

This is an interesting VTK learning exercise, so if the goal is learning then hopefully someone will answer your questions.

If the goal is to implement interactive tractography seeding in a VTK-based application then you are lucky: this is already implemented and available with full source code, to use, modify, extend, without any restrictions (BSD-type license), in C++ or Python, tested on Windows, Linux, and Mac, with free user and developer support (you can get help to get started with existing features and guidance for customizing it or implementing your own ideas based on it, without the need to redeveloping basic infrastructure), with surgical planning features, real-time interventional guidance (optionally, using Medtronic, BrainLab, or custom-built surgical navigation systems). More information: https://www.slicer.org, http://dmri.slicer.org/, and http://www.slicerigt.org.

1 Like

Hello,
Thanks for the reply. I am familiar with the Slicer.
But I want to implement the project in VTK. This will be helpful for me to work in VTK In future and understanding the timer and callback procedures.

I agree, it is a good approach to learn VTK on small projects and then when you are ready to implement a complete application then you can find suitable VTK-based software platform and utilize your experience there.