【図解】Qt Widgetsグラフィックスシーンで座標変換:QGraphicsItem::mapToItem()徹底解説


QGraphicsItem::mapToItem()は、Qt Widgetsにおけるグラフィックスシーンで座標変換を行うための重要な関数です。これは、あるアイテム内の座標を別のアイテム内の座標に変換するために使用されます。

機能

この関数は、2つの引数を取ります。

  1. item: 変換先のアイテム
  2. point: 変換対象の座標(QPointF型)

変換結果は、QPointF型で返されます。

使用方法

以下の例は、item1内の座標(50, 100)item2内の座標に変換する例です。

QPointF pointInItem1(50, 100);
QPointF pointInItem2 = item1->mapToItem(item2, pointInItem1);
  • 複数のアイテムが入れ子構造になっている場合、mapToItem()は、変換対象のアイテムまでのすべてのアイテムの変形を考慮して座標変換を行います。
  • アイテムがシーンルートの場合、mapToItem()scenePos()と同じ結果を返します。
  • 座標変換は、アイテムの現在の変形を考慮して行われます。

以下の例は、2つのアイテム(rect1rect2)を作成し、rect1内の座標(50, 100)rect2内の座標に変換するコードです。

#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsRectItem>

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

  QGraphicsScene scene;

  QGraphicsRectItem *rect1 = new QGraphicsRectItem(QRectF(0, 0, 100, 100));
  rect1->setPos(50, 50);
  scene.addItem(rect1);

  QGraphicsRectItem *rect2 = new QGraphicsRectItem(QRectF(0, 0, 50, 50));
  rect2->setPos(150, 50);
  scene.addItem(rect2);

  QPointF pointInRect1(50, 100);
  QPointF pointInRect2 = rect1->mapToItem(rect2, pointInRect1);

  qDebug() << "Point in rect1: " << pointInRect1;
  qDebug() << "Point in rect2: " << pointInRect2;

  QGraphicsView view(&scene);
  view.show();

  return app.exec();
}

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

Point in rect1: (50, 100)
Point in rect2: (25, 50)

これは、rect1内の座標(50, 100)が、rect2内の座標(25, 50)に変換されたことを示しています。



例 1: アイテム間の座標変換

この例では、2つの矩形アイテム (rect1rect2) を作成し、rect1 内の座標 (50, 100)rect2 内の座標に変換します。

#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsRectItem>

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

  QGraphicsScene scene;

  // アイテムを作成してシーンに追加
  QGraphicsRectItem *rect1 = new QGraphicsRectItem(QRectF(0, 0, 100, 100));
  rect1->setPos(50, 50);
  scene.addItem(rect1);

  QGraphicsRectItem *rect2 = new QGraphicsRectItem(QRectF(0, 0, 50, 50));
  rect2->setPos(150, 50);
  scene.addItem(rect2);

  // rect1 内の座標を rect2 内の座標に変換
  QPointF pointInRect1(50, 100);
  QPointF pointInRect2 = rect1->mapToItem(rect2, pointInRect1);

  // 変換結果を出力
  qDebug() << "Point in rect1: " << pointInRect1;
  qDebug() << "Point in rect2: " << pointInRect2;

  // シーンを表示
  QGraphicsView view(&scene);
  view.show();

  return app.exec();
}

例 2: アイテム内の座標をシーン内の座標に変換

この例では、rect1 内の座標 (50, 100) をシーン内の座標に変換します。

#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsRectItem>

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

  QGraphicsScene scene;

  // アイテムを作成してシーンに追加
  QGraphicsRectItem *rect1 = new QGraphicsRectItem(QRectF(0, 0, 100, 100));
  rect1->setPos(50, 50);
  scene.addItem(rect1);

  // rect1 内の座標をシーン内の座標に変換
  QPointF pointInRect1(50, 100);
  QPointF pointInScene = rect1->mapToScene(pointInRect1);

  // 変換結果を出力
  qDebug() << "Point in rect1: " << pointInRect1;
  qDebug() << "Point in scene: " << pointInScene;

  // シーンを表示
  QGraphicsView view(&scene);
  view.show();

  return app.exec();
}

例 3: シーン内の座標をアイテム内の座標に変換

この例では、シーン内の座標 (100, 150)rect1 内の座標に変換します。

#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsRectItem>

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

  QGraphicsScene scene;

  // アイテムを作成してシーンに追加
  QGraphicsRectItem *rect1 = new QGraphicsRectItem(QRectF(0, 0, 100, 100));
  rect1->setPos(50, 50);
  scene.addItem(rect1);

  // シーン内の座標を rect1 内の座標に変換
  QPointF pointInScene(100, 150);
  QPointF pointInRect1 = rect1->mapFromScene(pointInScene);

  // 変換結果を出力
  qDebug() << "Point in scene: " << pointInScene;
  qDebug() << "Point in rect1: " << pointInRect1;

  // シーンを表示
  QGraphicsView view(&scene);
  view.show();

  return app.exec();
}


以下に、QGraphicsItem::mapToItem() の代替方法をいくつか紹介します。

QTransform::map()

QTransform クラスは、2D 座標変換を行うための機能を提供します。QGraphicsItem::mapToItem() と同様に、QTransform::map() を使用して、あるアイテム内の座標を別のアイテム内の座標に変換することができます。

QTransform transform;
transform.translate(rect2->pos()); // rect2 の位置をオフセットとして設定
QPointF pointInRect1(50, 100);
QPointF pointInRect2 = transform.map(pointInRect1);

scenePos() と mapToScene() の組み合わせ

scenePos() 関数は、アイテムのシーン内の座標を取得します。一方、mapToScene() 関数は、アイテム内の座標をシーン内の座標に変換します。これらの関数を組み合わせることで、あるアイテム内の座標を別のアイテム内の座標に変換することができます。

QPointF pointInRect1(50, 100);
QPointF pointInScene = rect1->mapToScene(pointInRect1);
QPointF pointInRect2 = rect2->scenePos() + pointInScene - rect1->scenePos();

QGraphicsView の transform() メソッド

QGraphicsView クラスの transform() メソッドは、ビュー内の座標変換を取得します。このメソッドを使用して、ビュー内の座標をアイテム内の座標に変換することができます。

QPointF pointInScene(100, 150);
QPointF pointInView = view.transform().inverted(pointInScene);
QPointF pointInRect1 = rect1->mapFromScene(pointInView);

カスタム変換ロジック

上記の方法で解決できない場合は、カスタム変換ロジックを実装する必要があります。これは、より複雑な座標変換が必要な場合に役立ちます。

  • 複雑な座標変換が必要な場合は、カスタム変換ロジックを実装する必要があります。
  • ビュー内の座標をアイテム内の座標に変換する場合は、QGraphicsView::transform() メソッドを使用すると良いでしょう。
  • シーン内の座標をアイテム内の座標に変換する場合は、scenePos()mapToScene() の組み合わせを使用すると良いでしょう。
  • アイテム間の変換の場合は、QTransform::map() を使用すると、より柔軟な変換を行うことができます。
  • シンプルな変換の場合は、QGraphicsItem::mapToItem() を使用するのが最も簡単です。