Qt QGraphicsItem でHard-Edgeなギザギザ曲線を描画する

QtのQGraphicsEllipseなどのアイテムを描画すると、曲線部分でもどれだけ拡大していっても輪郭はなめらかに補間されたベクタ形式として表示されますが、これをラスタ形式のように輪郭がHard-Edgeでギザギザな輪郭をもったアイテムとして表示する方法を以下に紹介します。(かなり無理やりな方法です)

まず通常ならQGraphicsEllipseを使用する楕円描画を例に、ギザギザな輪郭の楕円描画を目標として説明します。

先に簡単に方法を説明すると

楕円の形状をQRegionに入れる
↓
QRegionからQPainterPathに変換
↓
QPainterPathをQGraphicsPainterItemにセットして表示

という流れになります。

サンプルコードは以下です。

// 楕円に内接する四角形(x, y, width, height)
const QRect ellipse( 10, 10, 40, 20 );
// QRegionへ変換
const QRegion ellipse_region( ellipse, QRegion::Ellipse );
// QPainterPathへ追加
QPainterPath path;
path.addRegion( ellipse_region );
path = path.simplified();
// QGraphicsPathItem作成
QGraphicsPathItem * item = new QGraphicsPathItem( path, 0, scene );

このようにすると通常だと下のようになめらかな曲線のアイテムを
f:id:nukesaq88:20130410192626p:plain
下のようにギザギザな輪郭曲線で描画できます。
f:id:nukesaq88:20130410192633p:plain

上記の画像のQGraphicsViewは400%x400%で拡大しています。


また上では説明していない

path = path.simplified();

の部分ですが、この行をコメントアウトすると下のようになります。
f:id:nukesaq88:20130410192639p:plain
これはQRegionに楕円を入れた時点でQRegionの内部ではただの矩形の集合として保持されるため、その矩形の輪郭がすべて描画されるためです。これを避けるためにQPainterPathのsimplified()という関数を使用しています。この関数は、上の結果をみれば分かりますが、内部のQPainterPath内部で隣接や領域が重複している部分をすべて結合したコピーを返す関数です。


今回の方法はQRegion内部では図形を単なる矩形の集合として表現していることを利用して、一旦QRegionに変換することで輪郭がギザギザな図形描画を実現しています。
なので単純な楕円以外の複雑な図形でもQRegionに変換しさえすれば同じ方法が使えるはずです。

参考
QRegion Class Reference | Documentation | Qt Project
QPainterPath Class Reference | Documentation | Qt Project