【初心者向け】Qt GUI描画で描画パスを分割する方法:QPainterPath::toSubpathPolygons()の使い方


QPainterPath::toSubpathPolygons()は、Qt GUIにおける描画パスを複数のポリゴンに変換する関数です。複雑なパスをよりシンプルなポリゴン群に分解することで、描画処理の効率化や特定の形状のみを抽出するといった用途に役立ちます。

関数詳細

QList<QPolygonF> QPainterPath::toSubpathPolygons(const QMatrix &matrix = QMatrix()) const;

この関数は以下の引数と戻り値を持ちます。

  • 戻り値: 変換されたポリゴン群を表すQList<QPolygonF>オブジェクト
  • matrix: 描画パスを適用する変換行列(デフォルトは単位行列)

使い方

  1. 描画パスを作成します。
  2. toSubpathPolygons()関数を呼び出し、変換行列をオプションで指定します。
  3. 変換されたポリゴン群を操作や描画に使用します。
QPainterPath path;
path.moveTo(0, 0);
path.lineTo(100, 0);
path.lineTo(100, 100);
path.lineTo(0, 100);
path.close();

QMatrix matrix;
matrix.rotate(45);

QList<QPolygonF> polygons = path.toSubpathPolygons(matrix);

// 各ポリゴンを操作または描画する
  • 変換行列を適用することで、ポリゴンを回転、拡大縮小、移動することができます。
  • 複雑なパスは、多くのポリゴンに分割される可能性があります。
  • ポリゴンは、閉じた形状と開いた形状の両方が含まれる可能性があります。


#include <QApplication>
#include <QPainterPath>
#include <QPolygonF>
#include <QWidget>

class ExampleWidget : public QWidget
{
public:
    ExampleWidget()
    {
        setFixedSize(200, 200);
    }

protected:
    void paintEvent(QPaintEvent *event) override
    {
        QPainter painter(this);

        // 矩形を描画パスに追加
        QPainterPath path;
        path.addRect(QRect(10, 10, 80, 80));

        // ポリゴン群に変換
        QList<QPolygonF> polygons = path.toSubpathPolygons();

        // 各ポリゴンを描画
        painter.setPen(Qt::red);
        for (const QPolygonF &polygon : polygons) {
            painter.drawPolygon(polygon);
        }
    }
};

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    ExampleWidget widget;
    widget.show();
    return app.exec();
}

例2: 星形を描画し、ポリゴンに変換する

#include <QApplication>
#include <QPainterPath>
#include <QPolygonF>
#include <QWidget>

class ExampleWidget : public QWidget
{
public:
    ExampleWidget()
    {
        setFixedSize(200, 200);
    }

protected:
    void paintEvent(QPaintEvent *event) override
    {
        QPainter painter(this);

        // 星形を描画パスに追加
        QPainterPath path;
        for (int i = 0; i < 5; ++i) {
            double angle = 2 * M_PI * i / 5;
            double radius = 50;
            double x = radius * cos(angle);
            double y = radius * sin(angle);
            if (i == 0) {
                path.moveTo(x, y);
            } else {
                path.lineTo(x, y);
            }
        }
        path.close();

        // ポリゴン群に変換
        QList<QPolygonF> polygons = path.toSubpathPolygons();

        // 各ポリゴンを描画
        painter.setPen(Qt::blue);
        for (const QPolygonF &polygon : polygons) {
            painter.drawPolygon(polygon);
        }
    }
};

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    ExampleWidget widget;
    widget.show();
    return app.exec();
}

説明

上記のコードは、それぞれ矩形と星形を描画し、それをポリゴンに変換して描画する例です。

  • QPainter::drawPolygon()を使用して、各ポリゴンを描画します。
  • QPainterPath::toSubpathPolygons()を使用して、描画パスをポリゴン群に変換します。
  • QPainterPath::addRect()QPainterPath::moveTo()/lineTo()/close()を使用して、描画パスを作成します。


代替方法の選択肢

  • パフォーマンスが重要な場合

    • QPainterPath::approximateOutline()関数を使用して、パスの輪郭を簡易的な線形近似で取得する。
    • カスタムのアルゴリズムを使用して、パスを効率的にポリゴンに分割する。
  • 特定の形状のみを抽出したい場合

    • QPainterPath::intersectedPath()関数を使用して、必要な形状のみを含む新しいパスを作成する。
    • QPainterPath::simplifiedPath()関数を使用して、パスを簡略化し、不要な部分を除去する。
    • QPainter::drawPath()関数を使用して、直接パスを描画する。
    • QPolygonF::fromRect()QPolygonF::fromCircle()などの関数を使用して、簡単な形状を直接作成する。

各方法の詳細

  • カスタムアルゴリズム
    パフォーマンスが特に重要である場合は、カスタムのアルゴリズムを使用してパスを効率的にポリゴンに分割することができます。

  • QPainterPath::approximateOutline()
    パスの輪郭を簡易的な線形近似で取得できます。

    QPainterPath outline = path.approximateOutline(10);
    painter.setPen(Qt::red);
    painter.drawPath(outline);
    
  • QPainterPath::simplifiedPath()
    パスを簡略化し、不要な部分を除去できます。

    QPainterPath simplifiedPath = path.simplifiedPath();
    painter.setPen(Qt::red);
    painter.drawPath(simplifiedPath);
    
  • QPainterPath::intersectedPath()
    必要な形状のみを含む新しいパスを作成できます。

    QPainterPath clipPath;
    clipPath.addRect(QRect(20, 20, 60, 60));
    QPainterPath newPath = path.intersectedPath(clipPath);
    painter.setPen(Qt::red);
    painter.drawPath(newPath);
    
  • QPolygonF::fromRect()/QPolygonF::fromCircle()
    矩形や円などの簡単な形状を直接作成したい場合に有効です。

    QPolygonF polygon = QPolygonF::fromRect(QRect(10, 10, 80, 80));
    painter.setPen(Qt::red);
    painter.drawPolygon(polygon);
    
  • QPainter::drawPath()
    最も単純な方法ですが、複雑なパスを描画すると処理が重くなる可能性があります。

    QPainter painter(this);
    painter.setPen(Qt::red);
    painter.drawPath(path);
    

選択の指針

上記のように、QPainterPath::toSubpathPolygons()以外にも様々な方法があります。最適な方法は、描画する形状の複雑さ、必要な処理速度、パフォーマンス要件などの状況によって異なります。

  • パフォーマンスが重要な場合は、ベンチマークテストを行い、最適な方法を検証することをお勧めします。
  • 複雑なパスを扱う場合は、複数の方法を組み合わせることも有効です。
  • 各方法の長所と短所を理解し、状況に応じて適切な方法を選択することが重要です。