I am working on a Qt project that involves using VTK to load multiple 3D .vtk files and display them as continuously changing data like 4D. I have successfully implemented the loop to load and display these files in a continuous manner. However, I now need to interact with this data while the loop is running, essentially treating it as if it were a 4D dataset.
To clarify, I have a separate thread that handles the looping and loading of .vtk files. While this thread is running, I am facing challenges when it comes to interacting with the displayed 4D data. Like a 4D ultrasound.
How can I achieve this level of interactivity while the loop is running?
this is my code snippet:
void UpdateAnimationCallback(vtkObject* caller, long unsigned int eventId, void* clientData, void* callData)
{
if (currentFrame <= numFrames) {
QString filePath = QDir::currentPath() + "/4dVolumes/";
QString filePrefix = "I0000042_";
QString fileName = filePath + filePrefix + QString::number(currentFrame) + ".vtk";
vtkSmartPointer<vtkStructuredPointsReader> vtkReader = vtkSmartPointer<vtkStructuredPointsReader>::New();
vtkReader->SetFileName(fileName.toUtf8().constData());
vtkReader->Update();
vtkSmartPointer<vtkColorTransferFunction> colorFun = vtkSmartPointer<vtkColorTransferFunction>::New();
vtkSmartPointer<vtkPiecewiseFunction> opacityFun = vtkSmartPointer<vtkPiecewiseFunction>::New();
vtkSmartPointer<vtkVolumeProperty> volumeProperty = vtkSmartPointer<vtkVolumeProperty>::New();
volumeProperty->SetColor(colorFun);
volumeProperty->SetScalarOpacity(opacityFun);
vtkSmartPointer<vtkGPUVolumeRayCastMapper> volumeMapper = vtkSmartPointer<vtkGPUVolumeRayCastMapper>::New();
volumeMapper->SetInputConnection(vtkReader->GetOutputPort());
vtkSmartPointer<vtkVolume> volume = vtkSmartPointer<vtkVolume>::New();
volume->SetMapper(volumeMapper);
volume->SetProperty(volumeProperty);
renderermpr->RemoveAllViewProps();
renderermpr->AddViewProp(volume);
renderWindow->Render(); // Render the scene before interaction
currentFrame++;
} else {
// Reset to the first frame and continue animation
currentFrame = 1;
}
}
class InteractionThread : public QThread
{
public:
vtkSmartPointer<vtkRenderWindowInteractor> interactor;
void run()
{
// Set up the interactor for interaction
interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
interactor->SetRenderWindow(renderWindow);
renderermpr->GlobalWarningDisplayOff();
renderermpr->ResetCamera();
renderermpr->GetActiveCamera()->Zoom(0.7);
renderermpr->GetActiveCamera()->SetViewUp(0, 0, -1);
renderermpr->GetActiveCamera()->Azimuth(90);
renderermpr->GetActiveCamera()->Roll(180);
//****************Interactor style****************
vtkSmartPointer<vtkInteractorStyleTrackballCamera> style_probe = vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New();
style_probe->GlobalWarningDisplayOff();
style_probe->AutoAdjustCameraClippingRangeOff();
style_probe->EnabledOn();
style_probe->On();
interactor->SetInteractorStyle(style_probe);
interactor->Initialize();
}
};
class AnimationThread : public QThread
{
public:
void run()
{
// Set up a timer to control the animation
vtkSmartPointer<vtkAnimationScene> animationScene = vtkSmartPointer<vtkAnimationScene>::New();
animationScene->SetModeToSequence();
animationScene->SetFrameRate(animationSpeed);
animationScene->SetStartTime(0);
animationScene->SetEndTime(numFrames - 1);
// Set up a callback function to update the animation
vtkSmartPointer<vtkCallbackCommand> callback = vtkSmartPointer<vtkCallbackCommand>::New();
callback->SetCallback(UpdateAnimationCallback);
animationScene->AddObserver(vtkCommand::AnimationCueTickEvent, callback);
// Start the animation
animationScene->Play();
}
};
int main(int argc, char* argv[])
{
QApplication a(argc, argv);
renderermpr = vtkSmartPointer<vtkRenderer>::New();
renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(renderermpr);
InteractionThread interactionThread;
interactionThread.start();
AnimationThread amimaThread;
amimaThread.start();
renderWindowInteractor->Initialize();
return a.exec();
}