知識は単独のものではなく、体系化されたものでなければなりません。私の個人的な概要と関連する経験の詳細については、このコラム「 Visual Studio」を参照してください。
この記事の主な目的は、VTK で作成した小さなボールを Qt インターフェースに表示し、その小さなボールを動かすことです。同時に、比較の便宜のために、動的なボールの動きの比較と観察を容易にするために、基準として静的なボールを追加します。
次のように、最初に最終エフェクトを解放します。
バージョン環境
- Win11
- Visual Studio 2022
- Qt 6.2.8_msvs2019_64
- VTK9.2.6
- プロジェクト名:
A
プロジェクトの目標は、座標がすでに利用可能であると仮定しx,y,z
、座標が変化すると、VTK のボールの位置が更新されることです。
プロジェクトの実現は次のとおりです。
3つの機能が設定されています。
void initVTK();
VTK ボール オブジェクトの初期化に使用されますvoid updateSpherePosition(double x, double y, double z);
ボールの位置を更新するvoid checkPositionChange();
位置が変化したかどうかを検出し、位置が変化した場合は更新します。変化しない場合は更新しません。
void initVTK();
関数には主に次のものが含まれます。
- // 球のソースと対応するマッパーを作成します
- // ボールを表すアクターを作成します
- // 参照オブジェクトを表すアクターを作成します
- // ボールと参照オブジェクトを表示するためのレンダラーとウィンドウを作成します
- // ボールと参照オブジェクトをレンダラーに追加します
- // vtkGenericOpenGLRenderWindow と QVTKOpenGLNativeWidget を関連付けます
void updateSpherePosition(double x, double y, double z);
関数には主に次のものが含まれます。
- //
vtkActor
のSetPosition
メソッドを使用して位置を更新します - // 再レンダリング
VTK において、renderWindow->Render();
レンダリング プロセスを実行するために使用されるコマンド。このメソッドは、データやビューの変更などによりシーンの一部を再描画する必要がある場合に必ず呼び出す必要があります。このプロジェクトの場合、ボールの位置が変わるたびに、ウィンドウを再レンダリングしてボールの表示位置を更新する必要があります。
void checkPositionChange();
関数には主に次のものが含まれます。
- // 位置変数を定義する
- // TODO: データ ソースから新しい x、y、z 座標値を取得し、newX、newY、newZ に保存します。
QElapsedTimer
// ここでは、クラス変数を使用してelapsedTimer
プログラムの実行時間を記録します。- // 位置が変化したかどうかを判断し、変化した場合は
updateSpherePosition(double x, double y, double z);
関数を呼び出してボールの位置を更新します
最後に、プロジェクトの鍵となるトリガー方法は、タイマーによってトリガーされます。タイマーはtimer
50ms ごとに関数をトリガーしcheckPositionChange();
、間接的に位置更新関数を呼び出してupdateSpherePosition(double x, double y, double z);
ボールの位置を更新します。
プロジェクトの構成と具体的なコードは次のとおりです。
A.ui
ui インターフェースは次のように構成され、Widget が構成されますQVTKOpenGLNativeWidget
。
構成方法がわからない場合は、私の構成記事を参照してください: [Visual Studio] Visual Studio と Qt を使用して Windows 上で VTK を構築する。
A.h
// A.h
#pragma once
#include <QtWidgets/QMainWindow>
#include "ui_A.h"
#include <vtkActor.h>
#include <vtkGenericOpenGLRenderWindow.h>
#include <QVTKOpenGLNativeWidget.h>
#include <qtimer.h>
#include <QElapsedTimer>
class A : public QMainWindow
{
Q_OBJECT
public:
A(QWidget* parent = nullptr);
~A();
// 将该函数添加为 public,以便在需要时更新小球位置
void updateSpherePosition(double x, double y, double z);
private slots:
void checkPositionChange(); // 添加一个新的槽函数,用于检查坐标变化
private:
Ui::AClass ui;
void initVTK(); // 将创建小球的过程抽象为一个单独的函数
vtkSmartPointer<vtkActor> sphereActor;
vtkSmartPointer<vtkActor> referenceActor;
vtkSmartPointer<vtkGenericOpenGLRenderWindow> renderWindow;
QTimer* timer;
QElapsedTimer elapsedTimer; // 定义一个变量来跟踪经过的时间,并使用这个时间来计算圆形路径上的点的坐标。
double lastX, lastY, lastZ;
};
A.cpp
// A.cpp
#include "A.h"
#include <vtkSphereSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkRenderer.h>
#include <vtkGenericOpenGLRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
A::A(QWidget* parent)
: QMainWindow(parent),
lastX(0), lastY(0), lastZ(0)
{
ui.setupUi(this);
// 配置 VTK 的初始设置
initVTK();
// 定时器,50ms 更新触发一次 checkPositionChange()
timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(checkPositionChange()));
timer->start(50);
// 开始记录经过的时间,并使用这个时间来计算圆形路径上的点的坐标
elapsedTimer.start();
}
A::~A()
{
}
void A::initVTK()
{
// 创建一个球体源和对应的 mapper
vtkSmartPointer<vtkSphereSource> sphereSource = vtkSmartPointer<vtkSphereSource>::New();
vtkSmartPointer<vtkPolyDataMapper> sphereMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
sphereMapper->SetInputConnection(sphereSource->GetOutputPort());
// 创建一个 actor 来表示小球
sphereActor = vtkSmartPointer<vtkActor>::New();
sphereActor->SetMapper(sphereMapper);
// 创建一个 actor 来表示参照物
referenceActor = vtkSmartPointer<vtkActor>::New();
referenceActor->SetMapper(sphereMapper);
referenceActor->SetPosition(0, 0, 0); // 参照物的位置固定在 (0, 0, 0)
// 创建一个渲染器和窗口来显示小球和参照物
vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
renderWindow = vtkSmartPointer<vtkGenericOpenGLRenderWindow>::New();
renderWindow->AddRenderer(renderer);
// 将小球和参照物添加到渲染器中
renderer->AddActor(sphereActor);
renderer->AddActor(referenceActor);
renderer->ResetCamera();
// 关联 vtkGenericOpenGLRenderWindow 和 QVTKOpenGLNativeWidget
ui.qvtkWidget->setRenderWindow(renderWindow);
}
void A::updateSpherePosition(double x, double y, double z) {
sphereActor->SetPosition(x, y, z);
renderWindow->Render();
}
void A::checkPositionChange() {
double newX, newY, newZ;
// TODO: 从你的数据源获取新的 x, y, z 坐标值,并存储在 newX, newY, newZ 中
double t = elapsedTimer.elapsed() / 1000.0; // convert ms to s
newX = 1 * cos(t);
newY = 1 * sin(t);
newZ = 0;
if (newX != lastX || newY != lastY || newZ != lastZ)
{
updateSpherePosition(newX, newY, newZ);
}
lastX = newX;
lastY = newY;
lastZ = newZ;
}
次のエラーが発生した場合: 未処理の例外が発生しました: 致命的なプログラムの終了が要求されました。
VTK の設定に問題がある可能性があります。VTK を設定するときに、[リリース] または [デバッグ] を選択することを思い出してください。まだわからない場合は、私の構成記事を参照してください: [Visual Studio] Visual Studio と Qt を使用して Windows 上で VTK を構築する。