Qt Widgetsで線とアイテムの隠蔽判定:QGraphicsLineItem::isObscuredBy()徹底解説


QGraphicsLineItem::isObscuredBy()は、引数で指定されたアイテムが自分自身を隠しているかどうかを判定する関数です。つまり、自分自身と引数のアイテムが重なり合っているかどうかを調べます。

戻り値

  • 重なり合っていない場合: false
  • 重なり合っている場合: true

詳細

QGraphicsLineItem::isObscuredBy()は、自分自身の形状引数のアイテムの形状を比較して判定を行います。形状の比較には、画家アルゴリズムと呼ばれるアルゴリズムが使用されます。

画家アルゴリズムは、以下の手順で2つの形状を比較します。

  1. それぞれの形状をスキャンラインに分解します。
  2. 各スキャンラインについて、どちらの形状がより多くのピクセルを覆っているかを調べます。
  3. 引数のアイテムが自分自身よりも多くのピクセルを覆っている場合、重なり合っていると判定します。

以下の例は、QGraphicsLineItem::isObscuredBy()を使用して、線と長方形が重なり合っているかどうかを判定するコードです。

QGraphicsLineItem line(0, 0, 100, 100);
QGraphicsRectItem rect(50, 50, 50, 50);

if (line.isObscuredBy(&rect)) {
  // 線と長方形が重なり合っている
} else {
  // 線と長方形が重なり合っていない
}
  • QGraphicsLineItem::isObscuredBy()は、Zオーダーを考慮しません。Zオーダーが大きいアイテムが小さいアイテムを隠している場合でも、QGraphicsLineItem::isObscuredBy()falseを返す可能性があります。
  • QGraphicsLineItem::isObscuredBy()は、パフォーマンスが比較的重い関数です。頻繁に呼び出す場合は、パフォーマンスに影響を与える可能性があることに注意が必要です。
  • Qt Widgets以外にも、Qt 3DやQt QMLなどの他のQtフレームワークでも同様の機能を提供している場合があります。


#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsLineItem>
#include <QGraphicsRectItem>

int main(int argc, char *argv[]) {
  QApplication app(argc, argv);

  // シーンを作成
  QGraphicsScene scene;

  // 線を作成
  QGraphicsLineItem line(0, 0, 100, 100);

  // 長方形を作成
  QGraphicsRectItem rect(50, 50, 50, 50);

  // シーンにアイテムを追加
  scene.addItem(&line);
  scene.addItem(&rect);

  // ビューを作成
  QGraphicsView view(&scene);
  view.show();

  // 線と長方形が重なり合っているかどうか判定
  if (line.isObscuredBy(&rect)) {
    // 線と長方形が重なり合っている
    qDebug() << "線と長方形が重なり合っています";
  } else {
    // 線と長方形が重なり合っていない
    qDebug() << "線と長方形が重なり合っていません";
  }

  return app.exec();
}

コード解説

  1. QApplicationオブジェクトを作成します。
  2. QGraphicsSceneオブジェクトを作成し、シーンを作成します。
  3. QGraphicsLineItemオブジェクトを作成し、線を作成します。
  4. QGraphicsRectItemオブジェクトを作成し、長方形を作成します。
  5. シーンに線と長方形を追加します。
  6. QGraphicsViewオブジェクトを作成し、ビューを作成します。
  7. ビューを表示します。
  8. line.isObscuredBy(&rect)を使用して、線と長方形が重なり合っているかどうかを判定します。
  9. 判定結果をコンソールに出力します。

実行結果

上記コードを実行すると、以下の出力がコンソールに出力されます。

線と長方形が重なり合っています
  • 線と長方形以外にも、様々なアイテムを使用してQGraphicsLineItem::isObscuredBy()を使用することができます。
  • このコードは、あくまでも動作例です。実際の使用状況に合わせて、コードを適宜変更する必要があります。


そこで、QGraphicsLineItem::isObscuredBy()の代替方法として、以下の方法が考えられます。

簡易判定

線と他のアイテムが重なり合っているかどうかを簡易的に判定する方法です。具体的には、以下の方法があります。

  • アイテムの形状が単純な場合、形状を比較して判定する
  • アイテムの境界線同士が重なり合っているかどうかを判定する

これらの方法は、QGraphicsLineItem::isObscuredBy()よりも高速ですが、精度が低くなる可能性があります。

以下のコードは、線と長方形が重なり合っているかどうかを、アイテムの境界線同士が重なり合っているかどうかを判定して簡易的に判定するものです。

bool isOverlappingSimple(const QGraphicsLineItem &line,
                        const QGraphicsItem &otherItem) {
  QRectF lineRect = line.boundingRect();
  QRectF otherItemRect = otherItem.boundingRect();
  return lineRect.intersects(otherItemRect);
}

カスタム判定

線と他のアイテムが重なり合っているかどうかを、独自のアルゴリズムで判定する方法です。この方法は、精度とパフォーマンスのバランスを調整することができます。

以下のコードは、線と長方形が重なり合っているかどうかを、画家アルゴリズムを使用して判定するものです。

bool isOverlappingCustom(const QGraphicsLineItem &line,
                        const QGraphicsItem &otherItem) {
  QPainterPath linePath = line.shape();
  QPainterPath otherItemPath = otherItem.shape();
  QPainter painter;
  painter.setRenderHint(QPainter::AntiAlias, true);
  painter.fillPath(otherItemPath, Qt::red);
  return painter.intersects(linePath);
}

Zオーダーを利用する

Zオーダーが大きいアイテムが小さいアイテムを隠している場合、QGraphicsLineItem::isObscuredBy()falseを返す可能性があります。Zオーダーを利用することで、この問題を回避することができます。

以下のコードは、線と長方形が重なり合っているかどうかを、Zオーダーを利用して判定するものです。

bool isOverlappingZOrder(const QGraphicsLineItem &line,
                        const QGraphicsItem &otherItem) {
  if (otherItem.zValue() >= line.zValue()) {
    return true;
  }
  return isOverlappingCustom(line, otherItem);
}

どの方法を選択するべきか

どの方法を選択するべきかは、状況によって異なります

  • Zオーダーが重要であれば、Zオーダーを利用するを選択します。
  • 精度が重要であれば、カスタム判定を選択します。
  • パフォーマンスが重要であれば、簡易判定またはカスタム判定を選択します。