Qt中使用VTK编程
1 控制台程序
既然是控制台,就无所谓Qt不Qt的了,使用的是vtkRenderWindow
,用什么开发工具和库都是一样的。当然,如果只是看图,也可以直接使用ImageView2
。直接用VTK的例子就可以.
2 GUI程序
但是,使用Qt的价值在于我们要编写GUI程序,我们要使用Qt提供的一系列的Widget。VTK的历史上,先后给出了好多个用于Qt的Widget组件:
QVTKWidget
QVTKWidget2
QVTKOpenGLWidget
QVTKOpenGLNativeWidget
QVTKOpenGLStereoWidget
对于我们来说,如果你使用的是Qt5.4以上的版本,VTK的版本是8.2以上,那么前面的都不需要考虑,只需要记住最后两个就好了。根据VTK的文档,建议一般情况下使用QVTKOpenGLNativeWidget
,特殊场景下可以使用SteroWidget
这个。
以前的版本,VTK还会编译出一个dll,你可以将它放到Qt的plugin目录里面,然后就可以在QtCreator的设计节目中看到一个QVTKWidget
了。这个新的VTK版本也没有了。所以新的用户也不要纠结怎么找不到了。QVTKOpenGLNativeWidget
是QOpenGLWidget
的派生类。现在我们先拖一个QWidget
控件,然后把它提升到QVTKOpenGLNativeWidget
就是了。
下面是一个典型的工作流程。假定ui->qvtkWidget
是我们在ui文件中定义的一个QVTKOpenGLNativeWidget
组件,那么这样使用:
// 创建source
vtkNew<vtkConeSource> cone;
// 创建Mapper
vtkNew<vtkPolyDataMapper> coneMapper;
coneMapper->SetInputConnection(cone->GetOutputPort());
// 创建Actor
vtkNew<vtkActor> coneActor;
coneActor->SetMapper(coneMapper);
// 创建Render
vtkNew<vtkRender> renderer;
renderer->AddActor(coneActor);
// 创建窗口
vtkNew<vtkGenericOpenGLRenderWindow> renwindow;
renwindow->AddRender(renderer);
renwindow->Render();
// 为Widget指定渲染窗口
ui->qvtkWidget->SetRenderWindow(renwindow.Get());
ui->qvtkWidget->update();
和Console程序的主要区别在于:
- 使用
vtkGenericOpenGLRenderWindow
代替了vtkRenderWindow
- 不需要
vtkRenderWindowInteractor
的创建和关联的操作了。不然会出错的。
下面是一段代码实际的代码, 改造自VTK里面的几个例子:
struct VisualizationForm::Implementation
{
QString _dataPath;
vtkSmartPointer<vtkNamedColors> _colors;
vtkSmartPointer<vtkGenericOpenGLRenderWindow> _renderWindow;
Implementation(const QString& data_path)
: _dataPath{data_path}
, _colors{vtkSmartPointer<vtkNamedColors>::New()}
, _renderWindow{vtkSmartPointer<vtkGenericOpenGLRenderWindow>::New()}
{
}
};
VisualizationForm::VisualizationForm(const QString &data_path, QWidget *parent)
: QWidget(parent)
, ui(new Ui::VisualizationForm)
, _impl{new Implementation(data_path)}
{
ui->setupUi(this);
ui->vtkWidget->setRenderWindow(_impl->_renderWindow);
connect(ui->btnClearWindow, &QPushButton::clicked, this, &VisualizationForm::onClearWindow);
connect(ui->btnCurPlane, &QPushButton::clicked, this, &VisualizationForm::onCutPlane );
...
}
void VisualizationForm::onCutPlane()
{
vtkNew<vtkNamedColors> colors;
vtkNew<vtkRenderer> renderer;
_impl->_renderWindow->AddRenderer(renderer);
renderer->SetBackground(colors->GetColor3d("SlateGray").GetData());
auto pl3d = loadData();
auto grid = dynamic_cast<vtkStructuredGrid *>(pl3d->GetOutput()->GetBlock(0));
// 定义切的平面. 通过定义平面的中心位置和法线方向来定义这个平面
vtkNew<vtkPlane> plane;
plane->SetOrigin(grid->GetCenter()); // 位置
plane->SetNormal(-0.287, 0, 0.9579); // 方向
// 定义cutter
vtkNew<vtkCutter> planeCut;
planeCut->SetInputData(grid);
planeCut->SetCutFunction(plane);
vtkNew<vtkDataSetMapper> cutMapper;
cutMapper->SetInputConnection(planeCut->GetOutputPort());
vtkNew<vtkActor> cutActor;
cutActor->SetMapper(cutMapper);
// 提取一个网格曲面
vtkNew<vtkStructuredGridGeometryFilter> compPlane;
compPlane->SetInputData(grid);
compPlane->SetExtent(0,100,0,100,9,9);
vtkNew<vtkPolyDataMapper> planeMapper;
planeMapper->SetInputConnection(compPlane->GetOutputPort());
planeMapper->ScalarVisibilityOff(); // 不显示值.
vtkNew<vtkActor> planeActor;
planeActor->SetMapper(planeMapper);
planeActor->GetProperty()->SetRepresentationToWireframe();
planeActor->GetProperty()->SetColor(colors->GetColor3d("Wheat").GetData());
// grid的outline
vtkNew<vtkStructuredGridOutlineFilter> outline;
outline->SetInputData(grid);
vtkNew<vtkPolyDataMapper> outlineMapper;
outlineMapper->SetInputConnection(outline->GetOutputPort());
vtkNew<vtkActor> outlineActor;
outlineActor->SetMapper(outlineMapper);
renderer->AddActor(outlineActor);
renderer->AddActor(planeActor);
renderer->AddActor(cutActor);
vtkCamera* camera = renderer->GetActiveCamera();
camera->SetPosition(5.02611, -23.535, 50.3979);
camera->SetFocalPoint(9.33614, 0.0414149, 30.112);
camera->SetViewUp(-0.0676794, 0.657814, 0.750134);
camera->SetDistance(31.3997);
camera->SetClippingRange(12.1468, 55.8147);
_impl->_renderWindow->Render();
}
vtkSmartPointer<vtkMultiBlockPLOT3DReader> VisualizationForm::loadData()
{
auto file_xyzname = QString("%1/combxyz.bin").arg(_impl->_dataPath);
auto file_qname = QString("%1/combq.bin").arg(_impl->_dataPath);
vtkNew<vtkMultiBlockPLOT3DReader> pl3d;
// 默认分别为100和202
pl3d->SetXYZFileName(file_xyzname.toStdString().c_str());
pl3d->SetQFileName(file_qname.toStdString().c_str());
auto scalarFunctionNumber = ui->scalarFunctionNumber->currentText().split('-').at(0).toInt();
auto vectorFunctionNumber = ui->vectorFunctionNumber->currentText().split(' ').at(0).toInt();
auto fieldNumber = ui->pointFieldId->currentText().split('-').at(0).toInt();
qDebug() << "scalarFunctionNumber=" << scalarFunctionNumber << ", vectorFunctionNumber=" << vectorFunctionNumber << ", fieldNumber=" << fieldNumber;
pl3d->SetScalarFunctionNumber(scalarFunctionNumber<=0 ? -1:scalarFunctionNumber); // 缺省值100, 密度
pl3d->SetVectorFunctionNumber(vectorFunctionNumber<=0 ? -1:vectorFunctionNumber); // 缺省值202, 动量
pl3d->AddFunction(fieldNumber<=0 ? -1:fieldNumber);
pl3d->Update();
return pl3d;
}