QGIS API: メモリプロバイダ

なにそれ?

メモリプロバイダはv1.5か1.6あたりでいつの間にかあった新しいプロバイダプラグインです(気がついたらあった、、、)。
どういうものかというと、通常のプロバイダはファイルとの入出力をやり取りするものですが、メモリプロバイダはその名のとおりメモリとの入出力を仲介します。
つまり、一時的なデータとして利用することができるレイヤーです。
QgsRubberBand要素は画面を更新すると消えてしまいますが、
メモリプロバイダレイヤーは明示的に削除、もしくはQGISを終了するまで生きているので、その間は他のレイヤーと同様に利用することができます。
当然編集/更新をサポートしているので、下書き的に要素を追加していくことができます。

メモリプロバイダを利用するには、
New Memory Layer”プラグインを利用すると良いでしょう。
手元のQGISがメモリプロバイダを利用できるかどうかを調べるには、QGISインストールディレクトリ以下のpluginsディレクトリにmemoryprovider.dllの有無を確認します。

APIから利用する

メモリプロバイダは、プラグインが何か一時的に要素を発生させるような用途に利用することができます。
以下に挙げるコードは、現在の表示範囲に10mグリッドを発生させる例です。

    def genLatLon(self):
        rect = self.canvas.extent()
        latlonLayer = QgsVectorLayer("LineString", "latlon_grid", "memory")
        QgsMapLayerRegistry.instance().addMapLayer(latlonLayer)
        latlonLayer.startEditing()
        provider = latlonLayer.dataProvider()
        provider.addAttributes(
            [QgsField("X", QVariant.Double), QgsField("Y", QVariant.Double)])
        x = (int(rect.xMinimum())/10)*10
        while x < rect.xMaximum():
            f = QgsFeature()
            f.setGeometry(QgsGeometry.fromPolyline(
                [QgsPoint(x, rect.yMinimum()), QgsPoint(x, rect.yMaximum())]))
            f.setAttributeMap({0: x, 1: None})
            x += 10
            latlonLayer.addFeature(f)
        
        y = (int(rect.yMinimum())/10)*10
        while y < rect.yMaximum():
            f = QgsFeature()
            f.setGeometry(QgsGeometry.fromPolyline(
                [QgsPoint(rect.xMinimum(), y), QgsPoint(rect.xMaximum(), y)]))
            f.setAttributeMap({0: None, 1: y})
            y += 10
            latlonLayer.addFeature(f)
        
        latlonLayer.commitChanges()
        latlonLayer.updateExtents()

3行目でメモリプロバイダレイヤを作成しています。
QgsVectorLayerコンストラクタの第3引数に"memory"を指定するとメモリプロバイダレイヤーになります。
メモリプロバイダの場合、QgsVectorLayerコンストラクタの第1引数は要素種別です。
指定できる要素は、QGIS v1.6では”Point”、”LineString”、”Polygon”です。
要素種別の文字列は、QGIS v1.6では大文字/小文字を区別するようですが、v1.7のソースコードを見る限りでは大文字/小文字は区別されなくなっているようです。
レイヤーを追加したら、あとは通常のレイヤーと同じように要素を追加することができます。

メモリレイヤーをCRSを指定して作成するには

QGIS 2.0以降は、新規にレイヤーを作成するときにCRSを指定しないと、CRSを指定するダイアログが表示されるようになりました。
つまり、レイヤーは必ず何らかのCRSを持たなくてはならなくなっています。

上記のように何も指定せずにメモリレイヤーを作成するといちいちダイアログが表示されるため煩わしいです。
そこでこのような場合はマップキャンバスのCRSを取得してレイヤーのCRSに設定したいところです。

ところが、CRS指定ダイアログは”レイヤー作成時”に指定されていないと聞いてくるという仕様のため、
あとでsetCrs()で指定するのでは結局ダイアログは表示されてしまいます。
したがって、以下のようにしてメモリレイヤーのURLで指定する必要があります。

   1:   # まずマップキャンバスのCRS番号を取得
   2:   # PostGISのIDで取得する
   3:   srsid = self.canvas.mapRenderer().destinationCrs().postgisSrid()
   4:   
   5:   # メモリレイヤーのURLを作成
   6:   # "?"以降にレイヤーオプションを指定する
   7:   # CRSを指定するには"crs="以降に指定するが、PostGISのIDを使うなら"crs=postgis:4612"などとする
   8:   # QgsCoordinateReferenceSystem::srsidで番号を取得したなら"crs=internal:"とするのか?
   9:   layerUrl = "point?crs=postgis:" + str(srsid)
  10:   
  11:   # メモリレイヤー作成
  12:   layer = QgsVectorLayer(layerUrl, "New memory layer...", "memory")

レイヤー作成時のURLにはフィールド定義も指定することができます。

  layerUrl = "point?field=piece:integer&field=sengo:integer&crs=postgis:" + str(srsid)
  layer = QgsVectorLayer(layerUrl, "piece", "memory")
アーカイブ