Qt Graphs改善点の理解と利用: 第1回

本稿は「QtGraphs 개선점 이해 및 활용하기 - 1편」韓国語版ブログの抄訳です。
 

今回のブログシリーズでは、Qt 6 で刷新された Qt Graphs モジュールについて説明します。目標は、Qt Graphs モジュールの基本的な概念とQt 6での構造的な改善点を説明することで、ユーザーが技術的な理解に基づいてより積極的に Qt Graphs を活用できるようにすることです。ブログは 2 回に分けて公開します。第1回では Qt Graphs の基本的な概念を解説し、第2回では具体的な改善点について詳しく説明します。

 

概要

Qt Graphsはデータの2D/3D可視化をサポートするモジュールです。このモジュールは Qt 5 で 2D は  Qt Charts モジュール、3D は Data Visualization モジュールとしてそれぞれ導入されましたが、Qt 6 ではQt Graphs という一つのモジュールに統合されました。Qt 6で統合は単純な機能統合ではなく、内部構造を改善し、以前より多くのメリットを享受できるようになりました。

この記事では、Qt の Model View Programming の観点から Qt Graphs モジュールを理解し、各要素を紹介します。また、この記事で扱った概念を練習するため、波のピークを視覚化する簡単な Qt Graphs の例を作成してみる時間を持ちます。例題作成はブログ第2回まで続きますので、最後までお付き合いいただければ幸いです。

 

Qt GraphsのQt 6の主な改善点は?

Qt 5 と比較して Qt 6 の Qt Graphs モジュールの代表的な利点は以下の通りです。

様々なプラットフォームでのパフォーマンスの安定化
Qt 5 の Qt Charts や Data Visualization モジュールで OpenGL 以外のエンジンを活用した性能加速には困難が存在しました。Qt 6 の大きな特徴の1つは、Rendering Hardware Interface (以下 RHI )を通じてレンダリングインターフェースを抽象化し、Mac、Linux、Windows など様々なプラットフォームで Qt が適切な レンダリングエンジンを選択できるようになったことです。 これが適用されたモジュールの1つがQt Quick 3D モジュールです。Qt Graphs モジュールは Qt Quick 3D モジュールを活用するように改編され、自然に RHI のメリットを享受できるようになりました。つまり、様々なプラットフォームでQt Graphsモジュールを使用しても、適切なレンダリングエンジンが選択され、パフォーマンス上の安定性を享受することができます


強化された3D視覚効果と拡張性
Qt GraphsがQt Quick 3Dを使用することで、Quick 3Dの視覚効果をQt Graphsに適用できるようになりました。 例えば、Scene Environment、Light Controlなどの機能をQt Graphsに適用することができます。 また、逆にQt GraphsをQuick 3Dアプリケーションに注入することもできます。このようにデータの3D視覚化機能が追加され、Quick 3Dとの互換性が拡張され、今後Quick 3Dに追加される機能についても適用及び拡張される可能性が高いです。

改善点についての具体的な内容は、第2回のブログで紹介していますので、参考にしてください。

Qt Graphsの基本概念

Model/Viewの視点から見たQt Graphs

Qt GraphsモジュールはQt Quick/Qt Widgetsと似たようなModel/View Programmingの構造を踏襲しています。これはViewをDataから分離して、より柔軟で拡張性のある開発構造を提供することを目的としています。Qt Graphsの開発方式を理解するには、各ViewとModelにどのような要素があるかを識別し、各要素の役割が何であるかを理解することが重要です。Qt 6.8基準Qt Graphsモジュールの要素をModel/View観点で図で表現すると下記のようになります。

image-2025-1-3_16-29-34

上で見ると、2D/3DのViewはそれぞれGraphsViewとGraphsItem3Dで定義されており、Modelの場合、2D/3DはそれぞれAbstractSeriesとAbstract3DSeriesで定義されています。Seriesの場合基本的にデータを所有してるのでModelですが、Viewの役割もします。QtGraphsの最上位Viewでは同時に複数のグラフを表現することができ、一つのグラフを表現するのが一つのSeriesです。個別グラフのView用の要素 (例えば、delegate、visibilityなど) をSeriesで設定することができます。

2D データと 3D データの比較

3Dデータは一般的に 2D データに比べて大きくて複雑です。通常、2D データは1次元配列に、3D の場合は2次元配列にデータが保存されます。2次元配列の場合、1次元配列に比べて容量も大きく、扱いも複雑です。このような特徴のため、3D グラフでは Data Proxy という追加の Model Layerが存在します。3Dのデータ管理コストが高いため、Data Proxy層を通じて複雑度を減らすためです。 この Data Proxyは、様々な3Dデータを直接解釈してSeriesに提供する役割を担っています。以下は、現在サポートされているいくつかのProxyタイプです:

  • Item Model Proxy: ItemModel タイプのデータを解釈するために使用されます。
  • Height Map Proxy:HeighMap データを解釈するために使用されます。

以下は Scatter3D の例題コードで、ビュー、モデル、データを階層的に表示するコードです。Scatter3D は一つの 3DSeries を保有しており、3DSeries はデータ特性に合う DataProxy を保有しています。ListModelは最終的にQAbstractItemModelを継承しているため、SeriesのDataProxyとしてItemModelScatterDataProxyを使用します。以下に示すItemModelProxyでは、ListModelの各要素のX、Y、Z値を解釈に使用されるRoleを割り当てています。

example.ui
Scatter3D {    anchors.fill: parent     Scatter3DSeries {        dataProxy: ItemModelScatterDataProxy {            itemModel: ListModel {                ListElement { x: 1; y: 2; z: 3 }                ListElement { x: 2; y: 4; z: 6 }                ListElement { x: 3; y: 6; z: 9 }            }             xPosRole: "x"            yPosRole: "y"            zPosRole: "z"        }    }}

 

コーディング実習で概念を身につけましょう

app_sample

本記事で説明した Qt Graphs の概念を理解するために、簡単なコーディング実習を行います。 Qt GraphsのSurface3Dを使用して、波のピークをリアルタイムで表示する簡単な QML アプリを作成してみましょう。 この例を通して、Qt Graphsの基本的な活用方法を理解し、リアルタイムデータの可視化について理解を深めることができるでしょう。 この例は、第2回のブログまで続きます。🌊 🌊

本編ではステップ1とステップ2を進めます:

  1. グラフモデルを作成 
  2. グラフビューを作成 
  3. カスタム3Dオブジェクトを追加 (ブログ2)
  4. 3D視覚効果を適用 (ブログ2)

全ての実習コードは https://github.com/NicolasJeon/ocean_wave_peak にありますので、参考にしてください。

グラフモデルを作成

まず、波を表現する 3D データモデルを設計する必要があります。 先に Qt Graphs の 3DモデルはSeries と Data Proxyで構成されていることを確認しました。ここで使う波のデータは QSurfaceDataProxyを継承して WaveDataProxy というカスタムプロキシを作成します。そして、この WaveDataProxy がSeries に提供されます。性能を考慮して DataProxy は C++ コードで実装し、QSurfaceDataProxy を継承して WaveDataProxy というカスタム Proxy タイプを定義します。以下は C++ ヘッダーファイルです:

WaveDataProvider.hpp
class WaveDataProxy : public QSurfaceDataProxy{    Q_OBJECT    QML_ELEMENT public:    WaveDataProxy();     void update()private:    WaveDataGenerator m_dataGen;};
 

WaveDataProxy クラスはデータを生成する WaveDataGenerator を持っています。WaveDataGenerator は別のスレッドで仮想的な波のデータを生成し、自分のキャッシュに保存した後、dataGenerated シグナルを発行します。 WaveDataProxy はこのシグナルを受け取り、キャッシュからデータを取得して更新します。

波データを生成するコードは ChatGPT-4o を活用して作成しました。完全なコードは下記のリンクを参照してください。

> Wave Equation

これでデータモデルに対する簡単な設定が終わりました。次は View を生成してみましょう。

グラフビューを作成

先ほど、グラフ空間全体を表すメインビューと、一つのグラフを表す Series が存在することを確認しました。メインビューである Surface3D と波を表す Series をそれぞれ以下のように作成します。単純化のため、120x120 サイズの平面に高さ-5~13M の空間のみを使用すると仮定します:

SeaSurfaceForm.ui
import QtQuickimport QtGraphs Item {    property alias seaSurfaceGraph : seaSurfaceGraphId    property alias surfaceSeriesId : surfaceSeriesId     anchors.fill: parent     Surface3D {        id: seaSurfaceGraphId        anchors.fill: parent         axisX: Value3DAxis { max: 120; min: 0 }        axisY: Value3DAxis { max: 13; min: -5 }        axisZ: Value3DAxis { max: 120; min: 0 }         Surface3DSeries {            id: surfaceSeriesId        }    }}
 

次は、ビューとデータモデルを統合する作業です。ここで作成した Surface3DSeries に前述の WaveDataProxy を下記のように注入します。

SeaSurface.qml
import QtQuickimport SeaAnalysis SeaSurfaceForm {    WaveDataProxy {        id: waveDataProxyId    }     Component.onCompleted: {        surfaceSeriesId.dataProxy = waveDataProxyId;     }}

 

コードを実行したら下記のように波を生成する Surface3D が表示されることが確認できます。まだ、Custom オブジェクトや Texture、視覚効果などを適用してないので、基本的な形だけです。第2回のブログで追加的な概念を説明し、これを例題に適用して、海の形にもっと近づけ、波の最高点を表す指標を追加します。

image-2025-1-13_1-40-47

まとめ

今回の記事では、Qt Graphsモジュールの基本的な概念を見てみました。 これは既存の Data Visualizationモジュールにもそのまま適用される概念です。Qt Graphsに適用されるモデル/ビュープログラミングの概念を紹介し、各要素がどのような役割を果たすかを確認できました。また、2D データと比較して 3D データを操作することの複雑さと、3D グラフのモデルを設計する際に、Data Proxy などの追加的な考慮事項について説明しました。最後に、この記事で説明した概念を応用して、Qt Graphs を使った波高分析アプリを部分的に作ってみました。

第2回のブログでは、Qt Graphs のモジュールに変更された技術的な改善点について説明し、これらの概念を本記事の波高分析アプリに追加的に適用する予定です。

もっと詳しく知りたいですか?

10日間の無料トライアルで Qt を直接体験してください!

Qt 6 トライアルする

Qt 専門家にお問い合わせする


Blog Topics:

Comments