QGIS API: レンダラV2

QGISは基本的にはビュアーです(と筆者はおもっている、、)。
なので、表示に関する機能は重要であると思われます。

QGISの開発者がそのように考えたかどうかはわかりませんが、
ベクタデータの表示機能(レンダラ)のバージョン2(新レンダラ)というものが導入され、要素の表示属性をより柔軟に操作できるようになりました。
それまでのレンダラ(旧レンダラ)とは設定方法が根本的に異なっており、両者に互換性はありません。
したがって、現在は若干ややこしい状態になっていますが、それでも新レンダラを導入したいという執念が感じられるというものです。

本記事では、新レンダラによる表示属性の操作を記述したいと思いますが、
すべてを網羅することはできませんので、随時追加していきたいとおもいます。

新レンダラ概要

新レンダラにはシンボルレイヤーというものが導入されています。
基本的なシンボル(点であれば「○」など)の場合はシンボルレイヤーは1つだけですが、
シンボルレイヤを複数作成して重ね合わせることでより複雑なシンボルを定義することができるようになっています。
カテゴリカルシンボルのように、シンボルがデータの何らかの属性値を表している場合は、
うまく組み合わせることで複数の属性値をシンボルで表現することができるでしょう。

新レンダラにおける基本的な設定手順は、まずシンボルの定義をシンボルレイヤーで行い、これらをシンボルクラスに追加し、
最終的にシンボルクラスをレンダラに設定するという流れになります。

以下に、それぞれの場合でのシンボル定義例を示します。

以下のコード例はすべてC++です。
なぜかPyhonからは見えないクラスがあったのでC++を使用しました。

基本マーカー(点要素)

基本マーカーとは、QGISのシンボル定義で”Simple marker”を選択した時に表示される基本図形で、
QgsSimpleMarkerSymbolLayerV2クラスが扱うことができるものです。

基本マーカー

基本マーカーの設定例は以下のとおりです。

   1: 	// centralwidgetはQgsMapCanvasオブジェクト
   2: 	QgsVectorLayer *pLayer = dynamic_cast<QgsVectorLayer *>( centralwidget->layer( 0 ) );
   3: 	if ( pLayer && pLayer->geometryType() == QGis::Point )
   4: 	{
   5: 		// シンボルのひな形を取得
   6: 		QgsSymbolV2 *pSymbol = QgsSymbolV2::defaultSymbol( QGis::Point );
   7: 
   8: 		// 第1引数で種類、第2引数は塗りつぶし色、第3引数は枠の色、第4引数は大きさ(ポイント単位)
   9: 		QgsSimpleMarkerSymbolLayerV2 *pSLayer = 
   			new QgsSimpleMarkerSymbolLayerV2( "pentagon", Qt::darkBlue, Qt::red, 10 );
  10: 		// シンボルレイヤーを入れ替え
  11: 		pSymbol->changeSymbolLayer( 0, pSLayer );
  12: 
  13: 		// シンボルをレンダラに設定
  14: 		QgsSingleSymbolRendererV2 *pRenderer = new QgsSingleSymbolRendererV2( pSymbol );
  15: 		// ベクタレイヤーのレンダラを設定
  16: 		pLayer->setRendererV2( pRenderer );
  17: 
  18: 		centralwidget->refresh();
  19: 	}
実行結果

実行結果

種別で指定できる名前は以下のとおりです。

名称シンボル
squareまたはrectangle矩形マーカー
diamondダイアマーカー
pentagon五角形マーカー
triangle三角形マーカー
equilateral_triangle正三角形マーカー
star星形マーカー
regular_star星形マーカー(レギュラー)
arrow矢印マーカー
filled_arrowhead横向き三角形マーカー
circle円形マーカー
cross+マーカー
xまたはcross2☓マーカー
lineラインマーカー
arrowheadくの字マーカー

ポリゴンの塗りつぶしを無しにする

ポリゴン描画のデフォルトは塗りつぶしですが、塗りつぶしてしまうとその後ろの要素や画像が見えなくなってしまいます。
以下に、枠線のみの描画を行う例を示します。

   1: 	QgsVectorLayer *pLayer = dynamic_cast<QgsVectorLayer *>( centralwidget->layer( 0 ) );
   2: 	if ( pLayer && pLayer->geometryType() == QGis::Polygon )
   3: 	{
   4: 		// 基本的なポリゴンシンボルレイヤー
   5: 		// 引数は塗りつぶし色、パターンブラシ、枠線の色、枠線の線種、枠線の線幅の順
   6: 		QgsSimpleFillSymbolLayerV2 *psLayer = new QgsSimpleFillSymbolLayerV2
   7: 			( QColor::fromRgb( 0, 0, 150 ), Qt::NoBrush, QColor::fromRgb( 0, 0, 150 ), 
   			Qt::SolidLine, 1.0 );
   8: 			
   9: 		QgsSymbolV2 *pSymbol = QgsSymbolV2::defaultSymbol( QGis::Polygon );
  10: 		pSymbol->changeSymbolLayer( 0, psLayer );
  11: 		QgsSingleSymbolRendererV2 *pRenderer = new QgsSingleSymbolRendererV2( pSymbol );
  12: 		pLayer->setRendererV2( pRenderer );
  13: 
  14: 		centralwidget->refresh();
  15: 	}
実行結果

実行結果

ポリゴンの網掛け

塗りつぶしではなく網掛け表示をする場合は担当クラスが変わります。
以下に例を示します。途中までは上記のコードと同じです。

   1: 	// 網掛け表示を担当するクラス
   2: 	QgsLinePatternFillSymbolLayer *psLayer = new QgsLinePatternFillSymbolLayer();
   3: 	
   4: 	// 斜線の間隔
   5: 	psLayer->setDistance( 10.0 );
   6: 	
   7: 	// 斜線の角度
   8: 	psLayer->setLineAngle( 45.0 );
   9: 
  10: 	// 斜線の線幅
  11: 	psLayer->setLineWidth( 0.1 );
  12: 
  13: 	pNewSymbol->changeSymbolLayer( 0, psLayer );
実行結果

実行結果(一部に設定)

なお、文字通り”網掛け”にするにはもうひとつシンボルレイヤー作成して重ねます。

SVGシンボル(点要素)

点要素を単純な図形ではなくアイコンのようなもので表示したい場合には、SVGファイルでアイコンを作成してそれを使用します。

QGISには組み込みのアイコンがすでに用意されているので、それを利用することもできますし、
自作して使用することもできます。

   1: 	QgsVectorLayer *pLayer = dynamic_cast<QgsVectorLayer *>( centralwidget->layer( 0 ) );
   2: 	if ( pLayer && pLayer->geometryType() == QGis::Point )
   3: 	{
   4: 		// SVGマーカーシンボルレイヤークラス
   5: 		QgsSvgMarkerSymbolLayerV2 *pmsl = new QgsSvgMarkerSymbolLayerV2();
   6: 
   7: 		// ファイルを直接指定する場合
   8: 		// 組み込みSVGシンボルを利用する場合もこれで
   9: 		pmsl->setPath( "C:/OSGeo4W/apps/qgis/svg/shogi/kaku.svg" );
  10: 		
  11: 		// 自作SVGをリソースに登録して使用することもできます
  12: 		pmsl->setPath( ":/svg/bozu.svg" );
  13: 		
  14: 		// アイコンサイズ
  15: 		pmsl->setSize( 10.0 );
  16: 		
  17: 		QgsSymbolV2 *pSymbol = QgsSymbolV2::defaultSymbol( QGis::Point );
  18: 		pSymbol->changeSymbolLayer( 0, pmsl );
  19: 		QgsSingleSymbolRendererV2 *pRenderer = new QgsSingleSymbolRendererV2( pSymbol );
  20: 		pLayer->setRendererV2( pRenderer );
  21: 
  22: 		centralwidget->refresh();
  23: 	}
実行結果

実行結果

複線(線要素)

ここではシンボルレイヤーを重ねる例として複線の描画を行なってみます。

以下に、寒冷前線を描画する例を示します。
この場合、単純な線とマーカーラインの組み合わせになります。

   1: 	QgsVectorLayer *pLayer = dynamic_cast<QgsVectorLayer *>( centralwidget->layer( 0 ) );
   2: 	if ( pLayer && pLayer->geometryType() == QGis::Line )
   3: 	{
   4: 		// まず単純な線のレイヤーを作成
   5: 		QgsSymbolV2 *pSymbol = QgsSymbolV2::defaultSymbol( QGis::Line );
   6: 		QgsSimpleLineSymbolLayerV2 *pSLayer1 = new QgsSimpleLineSymbolLayerV2( Qt::black );
   7: 		
   8: 		// 後のマーカーを線の中心にしたいので、マーカーのサイズ分オフセットしておく
   9: 		pSLayer1->setOffset( 2.0 );
  10: 		pSymbol->changeSymbolLayer( 0, pSLayer1 );
  11: 
  12: 		// マーカーラインクラス
  13: 		QgsMarkerLineSymbolLayerV2 *pSLayer2 = new QgsMarkerLineSymbolLayerV2();
  14: 		
  15: 		// マーカーラインに用いるマーカーはサブシンボルとして作成する
  16: 		QgsSymbolLayerV2 *pSubSLayer = new QgsSimpleMarkerSymbolLayerV2( 
  			"triangle", Qt::black, Qt::black, 4.0 );
  17: 		QgsSymbolV2 *pSubSymbol = QgsSymbolV2::defaultSymbol( QGis::Point );
  18: 		pSubSymbol->changeSymbolLayer( 0, pSubSLayer );
  19: 		
  20: 		// マーカーをマーカーラインに登録
  21: 		pSLayer2->setSubSymbol( pSubSymbol );
  22: 		
  23: 		// マーカーの間隔を設定
  24: 		pSLayer2->setInterval( 10.0 );
  25: 
  26: 		// マーカーラインのシンボルレイヤーを追加
  27: 		pSymbol->appendSymbolLayer( pSLayer2 );
  28: 
  29: 		QgsSingleSymbolRendererV2 *pRenderer = new QgsSingleSymbolRendererV2( pSymbol );
  30: 		pLayer->setRendererV2( pRenderer );
  31: 
  32: 		centralwidget->refresh();
  33: 	}
実行結果

実行結果

カテゴリ別シンボル

カテゴリ別シンボルとは、要素の属性ごとに表示シンボルを設定するものです。
したがって、プログラム側ではまずどのフィールドを対象にするかを決める必要があります。

また、カテゴリ分けされた後は個別の値のシンボルをそれぞれ設定することができますが、
それがめんどくさい場合、またはカテゴリ数が未知の場合などのためにQgsVectorColorRampV2クラス(の派生クラス群)が用意されています。
これはカラーパレットのようなもので、0.0~1.0の間の値を渡すと対応する色を返してくれます。

以下に、カテゴリ分けシンボルの例を示します。

   1: 	QgsVectorLayer *pLayer = dynamic_cast<QgsVectorLayer *>( centralwidget->layer( 0 ) );
   2: 	if ( pLayer )
   3: 	{
   4: 		// カテゴリリスト あとでレンダラに渡す必要がある
   5: 		QgsCategoryList lstCats;
   6: 		
   7: 		// カテゴリのユニークな値を取得
   8: 		// ここでは"CODE"フィールドを指定
   9: 		QList<QVariant> lstUniqueVals;
  10: 		pLayer->uniqueValues( pLayer->fieldNameIndex( "CODE" ), lstUniqueVals );
  11: 		
  12: 		// カラーランプ ここではグラデーションランプを使用。
  13: 		// デフォルトでは青 => 緑のグラデーションになる
  14: 		QgsVectorColorRampV2 *pRamp = new QgsVectorGradientColorRampV2();
  15: 		
  16: 		QgsSymbolV2 *pSymbol = QgsSymbolV2::defaultSymbol( pLayer->geometryType() );
  17: 		
  18: 		for ( int i = 0; i < lstUniqueVals.count(); i++ )
  19: 		{
  20: 			// シンボルを複製
  21: 			QgsSymbolV2 *pNewSymbol = pSymbol->clone();
  22: 
  23: 			// 現在のフィールドの値
  24: 			QVariant val = lstUniqueVals[i];
  25: 			
  26: 			// ランプから色を取得
  27: 			double d = i / (double)lstUniqueVals.count();
  28: 			pNewSymbol->setColor( pRamp->color( d ) );
  29: 			
  30: 			// 値とシンボルの組みをカテゴリリストに追加
  31: 			lstCats.append( QgsRendererCategoryV2( val, pNewSymbol, val.toString() ) );
  32: 		}
  33: 
  34: 		// カテゴリ分けレンダラにカテゴリリストを渡す
  35: 		QgsCategorizedSymbolRendererV2 *psLayer = new QgsCategorizedSymbolRendererV2( "CODE", lstCats );
  36: 		pLayer->setRendererV2( psLayer );
  37: 
  38: 		centralwidget->refresh();
  39: 	}
実行結果

実行結果

続く、、

レンダラV2は大変柔軟に設定が可能なので、上記以外にもいろいろな設定方法があるかと思われます。
また、上記では使用していないシンボルレイヤークラスがあるので、調べ次第随時追加していきたいとおもいます。

アーカイブ