How to tell VTK pipeline to use new vtkPolyData updated via TimerEvent?

江枫思渺然 提交于 2019-12-08 05:33:26

the problem is that the cells are not stored by pointer - when you call cells->InsertNextCell(polyLine); the data is copied, not pointed to, in order to create an efficient storage of the cells in an array (the whole implementation is actually in the header of vtkCellArray so you can check it out). So then when you update polyLine, it has no effect in the polydata, because the polydata have their own copy that you did not update. The following code works for me (you have to expose the polydata and the cellArray):

virtual void Execute(vtkObject *vtkNotUsed(caller), unsigned long eventId,
    void *vtkNotUsed(callData))
{
    if (vtkCommand::TimerEvent == eventId)
    {
        NextPoint(); // Add another point to polyData

        cells->Initialize(); // reset the cells to remove the old spiral
        cells->InsertNextCell(polyLine); // re-insert the updated spiral
        cells->Modified(); // required to update
        data->Modified(); // required to update
        ++this->TimerCount;
        cout << polyLine->GetNumberOfPoints() << endl;
        renderWindow->Render(); // refresh the render window after each update
    }
}

Yesterday I worked out an alternative solution using a vtkProgrammableDataObjectSource as DataSource. Tomj's solution is the more direct and simple solution... However, there is no C++ Example Code at vtk.org that explains how to use vtkProgrammableDataObjectSource and I had to work it out by trial and error. So I'll post it here, as it might help others:

#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkRenderingContextOpenGL2);
VTK_MODULE_INIT(vtkRenderingVolumeOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
VTK_MODULE_INIT(vtkRenderingFreeType);

#include <vtkSmartPointer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkConeSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkProperty.h>
#include <vtkPoints.h>
#include <vtkPolyLine.h>
#include <vtkProgrammableFilter.h>
#include <vtkCallbackCommand.h>
#include <vtkPolyDataStreamer.h>

#include <vtkProgrammableDataObjectSource.h>


vtkSmartPointer<vtkProgrammableDataObjectSource> pDOS = vtkSmartPointer<vtkProgrammableDataObjectSource>::New();
vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();

vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
vtkSmartPointer<vtkPolyLine> polyLine = vtkSmartPointer<vtkPolyLine>::New();

int numOfPoints = 0;
double t = 0;

void NextPoint() {
    double x = t * cos(t);
    double y = t * sin(t);
    points->InsertNextPoint(x, y, t);
    polyLine->GetPointIds()->InsertNextId(numOfPoints);

    numOfPoints++;
    t += 0.1;
}

void generateEllipse(void *caller) {
    vtkProgrammableDataObjectSource *pDOS = vtkProgrammableDataObjectSource::SafeDownCast((vtkObjectBase*)caller);

    vtkSmartPointer<vtkCellArray> cells = vtkSmartPointer<vtkCellArray>::New();
    cells->InsertNextCell(polyLine);

    vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New();
    polyData->SetPoints(points);
    polyData->SetLines(cells);

    pDOS->SetOutput(polyData);
}


int counter2 = 0;
void TimerCallbackFunction(vtkObject* caller, long unsigned int vtkNotUsed(eventId), void* clientData, void* vtkNotUsed(callData)) {
    cout << "timer callback: " << counter2 << endl;

// To avoid globals we can implement this later... 
//  vtkSmartPointer<vtkProgrammableDataObjectSource> pDOS =
//      static_cast<vtkProgrammableDataObjectSource*>(clientData);

    vtkRenderWindowInteractor *rwi =
        static_cast<vtkRenderWindowInteractor*>(caller);

    NextPoint();

    pDOS->Modified();
    rwi->Render();
    renderer->ResetCamera(); // Optional: Reposition Camera, so it displays the whole object

    counter2++;
}



int main(int argc, char** argv) {
    vtkSmartPointer<vtkRenderWindow> renderWindow =
        vtkSmartPointer<vtkRenderWindow>::New();

    vtkSmartPointer<vtkRenderWindowInteractor> rwi = vtkSmartPointer<vtkRenderWindowInteractor>::New();
    rwi->SetRenderWindow(renderWindow);


    pDOS->SetExecuteMethod(&generateEllipse, pDOS);

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

    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    actor->SetMapper(mapper);
    actor->GetProperty()->SetDiffuseColor(255, 255, 0);

    renderWindow->AddRenderer(renderer);
    renderer->AddActor(actor);
    renderer->ResetCamera();

    renderWindow->Render();

    // Add Timer Event...
    vtkSmartPointer<vtkCallbackCommand> timerCallback = vtkSmartPointer<vtkCallbackCommand>::New();
    timerCallback->SetCallback(TimerCallbackFunction);

    rwi->Initialize();
    rwi->CreateRepeatingTimer(100);
    rwi->AddObserver(vtkCommand::TimerEvent, timerCallback);


    // Start Displaying...
    rwi->Start();

    return 0;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!