我在动画制作过程中何时更新vtk绘图数据?

时间:2018-09-23 18:08:14

标签: c++ vtk

我目前正在为vtkChartXY中的几行设置动画,但是对于我的简单任务而言,我的表现却很差。我想知道的是,如何有效地更新绘图数据,以及应该使用哪种数据结构?我目前有一个QTimer(来自Qt的计时器),它会触发更新帧号并发送更新信号,该信号进入我的DepthChartRenderer::update函数,表示存在更新。然后,另一个计时器发出信号的自定义vtkCommand会根据第一个计时器的更新来更新图表数据。我不确定我的系统在哪里崩溃了,但是对于我的测试仪来说,性能却很糟糕(大约是30fps时的一半)。

这是DepthChartRenderer的头文件:

class DepthChartRenderer
{
   public:
    DepthChartRenderer(DepthChartView * depthChartView);

    /*
     * Initialize chart data structures and fill in data
     */
    void init();

    /*
     * Gives the signal for an update to occur.
     */
    void update();

    /*
     * Returns whether the view is currently visible to the user.
     */
    bool visible() const;

    /*
     * Displays the visualization to the user
     */
    void show();

    /*
     * Hides the visualizations from the user, destroying the window
     */
    void hide();

   private:
    /*
     * Update based on variables in the view.
     */
    bool updateExists;
    std::mutex updateMutex;

    /*
     * Updates the frame. Should only be called from the vtk command
     */
    void updateFrame();

    class UpdateFrameCallback : public vtkCommand
    {
       public:
        static UpdateFrameCallback * New()
        {
            UpdateFrameCallback * cb = new UpdateFrameCallback;
            return cb;
        }

        virtual void Execute(vtkObject * caller, unsigned long eventId, void * vtkNotUsed(callData));

        DepthChartRenderer * depthChart;
    };
    friend class UpdateFrameCallback;

    DepthChartView * m_depthChartView = nullptr;
    uint m_realTime;

    void initChart();
    void initBpDTable();
    void initCpDTables();

    std::map<std::string, std::vector<uint>> m_bpdAnimationFrames;
    std::map<std::string, std::vector<uint>> m_cpdAnimationFrames;

    vtkSmartPointer<vtkTable> m_bpdTable;
    std::vector<std::vector<vtkSmartPointer<vtkTable>>> m_cpdTables;
    vtkSmartPointer<vtkChartXY> m_chart;
    vtkSmartPointer<vtkContextView> m_view;

    vtkPlot * m_bpdLine;
    std::vector<std::vector<vtkPlot *>> m_cpdLines;

    struct Color {
        uint r;
        uint g;
        uint b;
    };

    std::vector<Color> colors{{255, 0, 0}, {0, 255, 0}, {0, 0, 255}};

    bool m_firstRender = true;
};

和来源(缩写):

DepthChartRenderer::DepthChartRenderer(DepthChartView * depthChartView)
    : updateExists(true),
      m_depthChartView(depthChartView),
      m_realTime(0),
      m_bpdAnimationFrames(),
      m_cpdAnimationFrames(),
      m_bpdLine(0),
      m_cpdLines()
{
}

void DepthChartRenderer::init()
{
    std::cout << "Init" << std::endl;
    m_view = vtkSmartPointer<vtkContextView>::New();
    m_view->GetRenderer()->SetBackground(1.0, 1.0, 1.0);

    initChart();
    initBpDTable();
    initCpDTables();

    m_view->GetScene()->AddItem(m_chart);
    m_view->GetRenderWindow()->SetMultiSamples(0);
    m_view->GetInteractor()->Initialize();

    vtkSmartPointer<UpdateFrameCallback> cb = vtkSmartPointer<UpdateFrameCallback>::New();
    cb->depthChart = this;
    m_view->GetInteractor()->AddObserver(vtkCommand::TimerEvent, cb);
    m_view->GetInteractor()->CreateRepeatingTimer(1000 / 60);

    m_view->GetInteractor()->Start();
}

void DepthChartRenderer::initChart()
{
    m_chart = vtkSmartPointer<vtkChartXY>::New();
    m_chart->GetAxis(vtkAxis::BOTTOM)->SetTitle("Depth");
    m_chart->GetAxis(vtkAxis::LEFT)->SetTitle("#BT");
}

void DepthChartRenderer::initBpDTable()
{
    m_bpdTable = vtkSmartPointer<vtkTable>::New();

    vtkSmartPointer<vtkFloatArray> arrX = vtkSmartPointer<vtkFloatArray>::New();
    arrX->SetName("X Axis");
    m_bpdTable->AddColumn(arrX);

    // Fill in the table with some example values
    int numPoints = 1;
    int numRows = 1;
    if (m_depthChartView != nullptr && m_depthChartView->model() != nullptr) {
        numRows = m_depthChartView->bpdSource()->size();
        numPoints = m_depthChartView->bpdSource()->at(0).second.size();
    }

    // Add a column for each DepthChart Frame
    for (int i = 0; i < numRows; ++i) {
        vtkSmartPointer<vtkFloatArray> arrC = vtkSmartPointer<vtkFloatArray>::New();
        auto name = "DepthChart-BpD-" + std::to_string(i);
        arrC->SetName(name.c_str());
        m_bpdTable->AddColumn(arrC);
    }
    m_bpdTable->SetNumberOfRows(numPoints);

    // Fill out x-axis data
    for (int j = 0; j < numPoints; ++j) {
        m_bpdTable->SetValue(j, 0, j);
    }
    // Fill out entire table with all DepthChart data
    std::vector<uint> data = {0};
    for (int i = 0; i < numRows; ++i) {
        data = m_depthChartView->bpdSource()->at(i).second;
        for (int j = 0; j < numPoints; ++j) {
            m_bpdTable->SetValue(j, i + 1, data[j]);
        }
    }
}

void DepthChartRenderer::initCpDTables()
{
    // Same as initBpDTable for more than one table
}

void DepthChartRenderer::update()
{
    // Assumes that the dataMutex has already been locked
    // Copy animation frames
    for (auto entry : m_depthChartView->m_bpdAnimationFrames) {
        m_bpdAnimationFrames[entry.first] = entry.second;
    }
    m_depthChartView->m_bpdAnimationFrames.clear();

    for (auto entry : m_depthChartView->m_cpdAnimationFrames) {
        m_cpdAnimationFrames[entry.first] = entry.second;
    }
    std::lock_guard<std::mutex> guard(updateMutex);
    updateExists = true;
}

void DepthChartRenderer::updateFrame()
{
    // Update existence of BpD plot
    if (m_bpdLine == nullptr && m_depthChartView->model()->showBpD()) {
        m_bpdLine = m_chart->AddPlot(vtkChart::LINE);
        m_bpdLine->SetColor(255, 0, 0, 255);
        m_bpdLine->SetWidth(2.0);
    } else if (m_bpdLine != nullptr && !m_depthChartView->model()->showBpD()) {
        m_chart->RemovePlot(m_chart->GetPlotIndex(m_bpdLine));
        m_bpdLine->Delete();
        m_bpdLine = nullptr;
    }

    // Update existence of CpD plot
    if (m_cpdLines.size() == 0 && m_depthChartView->model()->showCpD()) {
        for (uint lineIndex = 0; lineIndex < m_cpdTables.size(); ++lineIndex) {
            std::vector<vtkPlot *> algoLines;
            for (uint algoIndex = 0; algoIndex < m_cpdTables[lineIndex].size(); ++algoIndex) {
                auto cpdLine = m_chart->AddPlot(vtkChart::LINE);
                cpdLine->SetColor(colors[lineIndex].r, colors[lineIndex].g, colors[lineIndex].b, 255);
                cpdLine->SetWidth(1.0);
                m_chart->SetPlotCorner(cpdLine, 1);
                algoLines.push_back(cpdLine);
            }
            m_cpdLines.push_back(algoLines);
        }
    } else if (m_cpdLines.size() != 0 && !m_depthChartView->model()->showCpD()) {
        for (uint lineIndex = 0; lineIndex < m_cpdLines.size(); ++lineIndex) {
            for (uint algoIndex = 0; algoIndex < m_cpdLines[lineIndex].size(); ++algoIndex) {
                auto line = m_cpdLines[lineIndex][algoIndex];
                m_chart->RemovePlot(m_chart->GetPlotIndex(line));
                line->Delete();
            }
        }
        m_cpdLines.clear();
    }

    // Lock before getting update variables
    std::unique_lock<std::mutex> dataLock(m_depthChartView->dataMutex);
    auto animationId = m_depthChartView->m_animationId;
    auto animationFrame = m_depthChartView->m_animationFrame;
    auto depthChartViewRealTime = m_depthChartView->m_realTime;
    auto realTime = m_realTime;
    dataLock.unlock();
    // Unlock so that main thread can update variables

    // Update data of plots
    if (m_depthChartView != nullptr && m_depthChartView->model() != nullptr) {
        if (m_depthChartView->model()->showBpD()) {
            uint frameNumber = 0;
            if (animationId.compare("") != 0) {
                frameNumber = m_bpdAnimationFrames[animationId][animationFrame];
            } else if (depthChartViewRealTime != realTime) {
                frameNumber = m_depthChartView->bpdSource()->indexOfTime(depthChartViewRealTime);
            }
            m_bpdLine->SetInputData(m_bpdTable, 0, frameNumber + 1);
        }

        if (m_depthChartView->model()->showCpD()) {
            uint frameNumber = 0;
            if (animationId.compare("") != 0) {
                frameNumber = m_cpdAnimationFrames[animationId][animationFrame];
            } else if (depthChartViewRealTime != realTime) {
                frameNumber = m_depthChartView->cpdSource()->indexOfTime(depthChartViewRealTime);
            }

            for (uint lineIndex = 0; lineIndex < m_cpdLines.size(); ++lineIndex) {
                for (uint algoIndex = 0; algoIndex < m_cpdLines[lineIndex].size(); ++algoIndex) {
                    m_cpdLines[lineIndex][algoIndex]->SetInputData(m_cpdTables[lineIndex][algoIndex], 0,
                                                                   frameNumber + 1);
                }
            }
        }

        m_chart->RecalculateBounds();
        m_chart->Modified();
    }
}

bool DepthChartRenderer::visible() const
{
    return m_view != nullptr;
}

void DepthChartRenderer::show()
{
    if (m_view != nullptr)
        return;
    init();
}

void DepthChartRenderer::hide()
{
    if (m_view == nullptr)
        return;
    m_view->Delete();
    m_view = nullptr;
}

void DepthChartRenderer::UpdateFrameCallback::Execute(vtkObject *, unsigned long eventId, void * vtkNotUsed(callData))
{
    if (vtkCommand::TimerEvent != eventId)
        return;

    std::unique_lock updateLock(depthChart->updateMutex);
    bool doUpdate = depthChart->updateExists;
    depthChart->updateExists = false;
    updateLock.unlock();

    if (!doUpdate)
        return;
    depthChart->updateFrame();
}

我的整体架构存在缺陷吗?或者我缺少一些简单的东西破坏了我的动画表现?

0 个答案:

没有答案