LBes
LBes

Reputation: 3456

Apply transformation to PolyData

I want to be able to apply tranformations to Polydata but no matter how I try to do it, it just doesn't work.

Here is what I have for "drawing" my polydata in a class call Drawing.cpp:

Drawing.h

vtkSmartPointer<vtkPlane> clipPlane; 
vtkSmartPointer<vtkImplicitPlaneRepresentation> planeRep; 
vtkSmartPointer<vtkActor> actorPlaneSource; 
vtkSmartPointer<vtkActor> mainActor; 

vtkSmartPointer<vtkTransformPolyDataFilter> transformFilter; 
vtkSmartPointer<vtkTransform> translation ; 
vtkContextView* ctxView ; 
vtkRenderWindow* win ; 
vtkRenderer* ren ; 
vtkCamera* cam ; 
vtkSmartPointer<vtkPolyData> inputPolyData;

Then the read function is called and starts the rendering, here is the function in drawing.cpp:

void Drawing::read(){ 

        std::string filename = BUNNY; 
        // Read all the data from the file 
        vtkSmartPointer<vtkXMLPolyDataReader> reader =vtkSmartPointer<vtkXMLPolyDataReader>::New(); 
        reader->SetFileName(filename.c_str()); 
        reader->Update(); 
        inputPolyData = reader->GetOutput(); 

        cout << "File Found and Loaded : " << filename << endl ; 

        vtkSmartPointer<vtkTransform> translation = vtkSmartPointer<vtkTransform>::New(); 
        translation->Translate(0.3, -0.05, 0); 
        transformFilter = vtkSmartPointer<vtkTransformPolyDataFilter>::New(); 
        //transformFilter->SetInputConnection(reader->GetOutputPort()); 
        transformFilter->SetInputData(inputPolyData); 
        transformFilter->SetTransform(translation); 
        //transformFilter->Update(); 

        vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New(); 
        mapper->SetInputConnection(transformFilter->GetOutputPort()); 

        mainActor = vtkSmartPointer<vtkActor>::New(); 
        mainActor->SetMapper(mapper); 

        ren->AddActor(mainActor); 

        vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New(); 
        iren->SetRenderWindow(win); 
        vtkInteractorStyleMultiTouchCamera *style = 
        vtkInteractorStyleMultiTouchCamera::New(); 
        iren->SetInteractorStyle(style); 

        //Start the event loop 
        iren->Initialize(); 
        iren->Start(); 

        defineClipping(); 
        win->PolygonSmoothingOn(); 
        win->Render(); 
        win->Start(); 
} 

From this, I have an other thread running a server that gets messages and has a pointer to my drawing object and is supposed to call one of these three functions depending on the message it gets from its clients:

void Drawing::scale(float k){ 
        vtkSmartPointer<vtkTransform> transform =vtkSmartPointer<vtkTransform>::New(); 
        transform->Scale(5,1,1); 
        vtkSmartPointer<vtkTransformFilter> transformFilter = vtkSmartPointer<vtkTransformFilter>::New(); 
        transformFilter->SetInputConnection(cone->GetOutputPort()); 
        transformFilter->SetTransform(transform); 
        mapper->SetInputConnection(transformFilter->GetOutputPort()); 
        ren->GetActiveCamera(); 
} 

void Drawing::translate(float x, float y, float z){ 
        cout << "Translate: " << x << " - " << " - " << y << " - " << z << endl ; 
        vtkSmartPointer<vtkTransform> transform1a = vtkSmartPointer<vtkTransform>::New(); 
        //transform1a->Translate(x,y,z); 
        //transformFilter->SetTransform(transform1a); 
        //transformFilter->Update(); 
        double* position = mainActor->GetPosition(); 
        mainActor->SetPosition(position[0]+x,position[1]+y,position[2]+z); 
} 

void Drawing::rotate(float x, float y, float z){ 
        cout << "Rotate: " << x << " - " << " - " << y << " - " << z << endl ; 
        vtkSmartPointer<vtkTransform> transform1a = vtkSmartPointer<vtkTransform>::New(); 
        //transform1a->PostMultiply(); 
        //transform1a->RotateX(x); 
        //transform1a->RotateY(y); 
        //transform1a->RotateZ(z); 
        //mainActor->SetUserTransform(transform1a); 
        mainActor->RotateWXYZ(20,1,0,0); 

}

None of these functions work because nothing is changing in the rendering windows unless I click in the rendering window itself. So I thought maybe I should try and add to every transformation functions: ctxView->Render(); But when I do I get:

Error the ressource is already busy.

I'm a newbie in VTK but I find it weird that I can't even do a simple transformation to an object. Would really like to get some help with that.

EDIT: Ok so after hours of trying different things I have notices that if I comment out the line iren->Start(); my rotations and translations are called. However, the program closes as soon as there done and I cannot interact with my window anymore. Would you have some insights on that?

Thanks in advance.

Upvotes: 1

Views: 4126

Answers (4)

LBes
LBes

Reputation: 3456

So thanks to the help of people here and some research with the code and documentation I've figured that this part in my code was responsible for nothing happening when trying to rotate/translate/scale my Polydata:

//Start the event loop
iren->Initialize();
iren->Start();

Indeed the start() method of the vtkRenderWindowInteractor is blocking and therefore no matter what I could call afterward was not processed. Getting rid of it allows me to call my transformation functions. Yet with the loss of the possible interaction with the data and the window closing right after every transformation is applied.

Upvotes: 1

asdfasdf
asdfasdf

Reputation: 804

Since your problem is the interactor, try doing this hack. Waht it does is create a timer for the interactor that will help get out of the start blocking method :

class CommandSubclass2 : public vtkCommand
{
  public:
    vtkTypeMacro(CommandSubclass2, vtkCommand);

    static CommandSubclass2 *New()
    {
        return new CommandSubclass2;
    }

    void Execute(vtkObject *vtkNotUsed(caller), unsigned long vtkNotUsed(eventId), 
                    void *vtkNotUsed(callData))
    {
        std::cout << "timer callback" << std::endl;
        renderWindowInteractor->ExitCallback();
    }
};

// in your main

vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New(); 
iren->SetRenderWindow(win); 

iren->CreateRepeatingTimer(1);

 vtkSmartPointer<CommandSubclass2> timerCallback = 
      vtkSmartPointer<CommandSubclass2>::New();
iren->AddObserver ( vtkCommand::TimerEvent, timerCallback );

vtkInteractorStyleMultiTouchCamera *style = 
        vtkInteractorStyleMultiTouchCamera::New(); 
iren->SetInteractorStyle(style); 



while(true)
{
    iren->Start();     
    ren->Render();
}

Probably not the good way of doing it, but I don't know any other way to get out of the interactor blocking method start()

Upvotes: 1

Cory Quammen
Cory Quammen

Reputation: 1298

As flaviu2 wrote, you absolutely need to call

ren->Render();

after updating your vtkTransform. Renderers do not watch VTK objects that are being rendered to see if anything has been updated. You need to call the Render() member function explicitly.

Beware threading. It is possible to use threading, but most of VTK is not thread safe, and it is probably going to cause you some headaches. To separate this problem from potential problems caused by using different threads to update objects, I would try to get this working without threading, and update this question if you still encounter problems.

Upvotes: 1

Flaviu_
Flaviu_

Reputation: 1371

Yes, I could try to give a little code that made rotations to a polydata, but I guess that is something different from your pipeline (I am using vtkImageReslice object as m_pReslice):

int nExtent[3];
double dSpacing[3];
double dOrigin[3];

m_pReader->GetOutput()->GetSpacing(dSpacing);
m_pReader->GetOutput()->GetOrigin(dOrigin);
m_pReader->GetOutput()->GetDimensions(nExtent);

double dCenter[3];
dCenter[0] = dOrigin[0] + dSpacing[0] * 0.5 * nExtent[0];   // nExtent[0] is width
dCenter[1] = dOrigin[1] + dSpacing[1] * 0.5 * nExtent[1];   // nExtent[1] is height
dCenter[2] = dOrigin[2] + dSpacing[2] * 0.5 * nExtent[2];   // nExtent[2] is depth

vtkSmartPointer<vtkTransform> pTransform = vtkSmartPointer<vtkTransform>::New();
pTransform->PreMultiply();

int nDirection = CDirectionDlg::GetDirection();
if(CDirectionDlg::DIR_AXIAL == nDirection)
{
    pTransform->Translate(dCenter[0], 0, dCenter[2]);
    pTransform->RotateY(180);
    pTransform->Translate(-dCenter[0], 0, -dCenter[2]);
}
else
{
    pTransform->Translate(dCenter[0], dCenter[1], 0);
    pTransform->RotateZ(180);
    pTransform->Translate(-dCenter[0], -dCenter[1], 0);
}

m_pReslice->SetResliceTransform(pTransform);
m_pReslice->SetInterpolationModeToLinear();
m_pReslice->Update();

Consider that another way to rotate an object in a view is to moving camera ... I hope it help you.

Upvotes: 1

Related Questions