QGISのプラグイン作成 ラバーバンドサンプル


はじめに

このサンプルプラグインでは、ラバーバンドを使ってオブジェクトを描画することができます。
描画が終わったら、Pythonコンソールにオブジェクトの座標を表示します。


使い方

f:id:Chiakikun:20210514003656p:plain

ここからプラグインのzipファイルをダウンロードしてインストールします。プラグインを実行した状態で、マップ上でマウスの左ボタンを押下すると図形を描画できます。
右ボタンを押下で決定され、Pythonコンソールにオブジェクトの座標が表示されます。


コード

class RubberbandSample(QgsMapTool):

    def printGeometry(self, geom):
        print(geom)


    def start(self):
        maptool = RubberBandClass(self.iface, self.canvas, self.objtype)
        maptool.getObject.connect(self.printGeometry)

~略~

    def __init__(self, iface):
        self.objtype     = QgsWkbTypes.PolygonGeometry # QgsWkbTypes.PointGeometry, QgsWkbTypes.LineGeometry, QgsWkbTypes.PolygonGeometry
~略~

class RubberBandClass(QgsMapTool):
    getObject = pyqtSignal(QgsGeometry)

    def __init__(self, iface, canvas, type):
        QgsMapTool.__init__(self, canvas)

        self.canvas = canvas
        self.iface = iface
        self.type = type

        self.myRubberBand = None


    def canvasMoveEvent(self, event):
        if self.myRubberBand == None: # 一度も左ボタンをクリックしてない時にこのメソッドが呼ばれた場合
            return

        # 地物の描画中に、マウスカーソルを追って形状が変わるように
        point = self.canvas.getCoordinateTransform().toMapCoordinates(event.pos())
        self.myRubberBand.movePoint(point)


    def canvasPressEvent(self, event):
        currentPos = self.toMapCoordinates(event.pos())

        # 地物の最初の一点目
        if event.button() == Qt.LeftButton and self.myRubberBand == None:
            if self.type == QgsWkbTypes.PointGeometry:
                self.getObject.emit(QgsGeometry.fromPointXY(currentPos))
                return
            else:
                self.myRubberBand = QgsRubberBand( self.canvas, self.type )
                self.myRubberBand.setColor( QColor(255, 0, 0, 128) )
                self.myRubberBand.addPoint( QgsPointXY(currentPos) )

        # 地物の二点目以降
        if event.button() == Qt.LeftButton and self.myRubberBand.numberOfVertices() > 0:
            self.myRubberBand.addPoint( QgsPointXY(currentPos) )

        # オブジェクト確定
        if event.button() == Qt.RightButton:
            if self.myRubberBand == None:
                return

            self.getObject.emit(self.myRubberBand.asGeometry()) # ラバーバンドのオブジェクト取り出し


            self.canvas.scene().removeItem(self.myRubberBand) # ラバーバンドで描いた図形はもう必要ないので消す
            self.myRubberBand = None


    def deactivate(self):
        try: # 右クリックしてmyRubberBandを解放していた場合は例外発生するので。
            self.myRubberBand.reset(True)
        except:
            pass

14行目 このプラグインで描画するオブジェクトのタイプを指定します。ここではポリゴンを描画する設定になっていますが、ポイントを描画したい(ラバーバンドの意味が無いですが)場合はQgsWkbTypes.PointGeometryを、ラインを描画したい場合はQgsWkbTypes.LineGeometryを指定してください。
9行目 オブジェクトを描画し終わったら呼ばれるメソッドを登録します。
43行目 マップで左クリックすると、オブジェクトの1点目が描画されます。
35行目 ラバーバンドが表示されている状態でマウスを動かすと、ラバーバンドも一緒に動きます。
53行目 左クリックで次のノードを決定します。
61行目 オブジェクトの描画を終了します。
4行目 描画したオブジェクトの座標がPythonコンソールに表示されます。
ソース全文


マルチオブジェクトを描画したい場合

インストール直後のサンプルではマルチオブジェクトを描画することはできませんが、上のコードの8行目を以下の様に書き換えると、一つオブジェクトを書き終えた後に右クリックで決定するのではなく、左ボタンをダブルクリックすることで、2つ目のパーツを描画することができます。

        maptool = RubberBandClassEx(self.iface, self.canvas, self.objtype)

最後までご覧頂き、ありがとうございました

QGISのプラグイン作成 スクリーンショットサンプル(ファイル毎)


はじめに

このサンプルは、フォルダ内に格納されているshpを表示して、そのスクリーンショットを画像保存するプラグインです。


使い方

ここからzipファイルをダウンロードしてインストールします。インストールできたら、screenshot_sample.pyの53、54行目を適当に編集してください。

        self.inputdir =  'shpが格納されているフォルダパス' 
        self.outputdir = '画像の保存先のファイルパス' 

設定したらプラグインを再読み込みして実行してください。読み込んだshpのレイヤ全体を表示してスクリーンショットが撮られ、保存先に画像が保存されます。


コード

class ScreenShotSample(QgsMapTool):

    def exportMap(self): 
        self.canvas.saveAsImage(self.outputdir + '\{}.png'.format(self.layername) ) 
        QgsProject.instance().removeMapLayer(qgis.utils.iface.activeLayer()) 
        if len(self.filelist) > self.count: 
            self.setNextFeatureExtent() 
        else: 
            self.canvas.mapCanvasRefreshed.disconnect( self.exportMap ) 


    def setNextFeatureExtent(self): 
        self.layername, ext = os.path.splitext(os.path.basename(self.filelist[self.count])) 
        self.layer = self.iface.addVectorLayer(self.filelist[self.count], self.layername, "ogr") 
        self.iface.zoomToActiveLayer()  	
        self.count += 1 


    def start(self):
        self.ext = '.shp'
        self.inputdir =  'shpが格納されているフォルダ' 
        self.outputdir = '画像の保存先フォルダ' 

        self.filelist = glob.glob(self.inputdir + "\*" + self.ext) 
        if len(self.filelist) == 0: return 
        self.count = 0 
        self.canvas.mapCanvasRefreshed.connect( self.exportMap ) 
        self.setNextFeatureExtent() 
        
~略~

24行目 21行目で指定したフォルダ内のshpファイルのパスを取得して...
14、15行目 マップにファイルを全体表示しています。
4行目 表示が完了したら、スクリーンショットを保存します。
5行目 撮影終わったので、マップからレイヤを削除して...
7行目 次のファイルを読みに行きます。
ソース全文


最後までご覧頂き、ありがとうございました

QGISのプラグイン作成 インターセクトによる地物選択


はじめに

調査ツールの「場所による選択」と同じような、選択したオブジェクトに交差するオブジェクトを抽出するプラグインのサンプルを作成しました。


このサンプルの使い方

ここからzipファイルをダウンロードしてインストールします。インストールできたら、intersectselect_sample.pyの以下の部分を変更します。

        selectLayer = QgsProject.instance().mapLayersByName('〇〇')[0]
        intersectLayer = QgsProject.instance().mapLayersByName('〇〇')[0]

1行目の〇〇には、抽出したいオブジェクトのレイヤ名を設定してください。
2行目の〇〇には、オブジェクトの抽出に使うオブジェクトのレイヤ名を設定してください。

f:id:Chiakikun:20200607141639p:plain

ポリゴンを選択した状態でプラグインを実行すると...

 

f:id:Chiakikun:20200607141651p:plain

選択したポリゴンに重なるポイントの地物が選択状態になります。


コード

~略~
    def intersectSelect1(self, selectLayer, intersectLayer):
        selectLayer.removeSelection()

        sel = []
        for feat in intersectLayer.selectedFeatures():
            geom = feat.geometry()

            cands = selectLayer.getFeatures(QgsFeatureRequest().setFilterRect(geom.boundingBox()))
            for sf in cands:
                if geom.intersects(sf.geometry()):
                    sel.append(sf.id())
            selectLayer.select(sel)
~略~

    def start(self):
        selectLayer = QgsProject.instance().mapLayersByName('〇〇')[0]
        intersectLayer = QgsProject.instance().mapLayersByName('〇〇')[0]

        self.intersectSelect1(selectLayer, intersectLayer)
~略~

9行目 選択したオブジェクトの矩形で、抽出したいレイヤのオブジェクトを大雑把に抽出して...
11行目 矩形で抽出できたオブジェクトが、選択したオブジェクトに交差すれば、IDを取得して...
13行目 取得できたIDのレコードを選択状態にしています。
ソース全文


遅いので他の方法を...

「場所による選択」と比べると処理時間がとてもかかるので、プラグインから「場所による選択」を実行する方法も載せます。


コード2

~略~
    def intersectSelect2(self, selectLayer, intersectLayer):
        qgis.processing.run("native:selectbylocation",\
            {\
            'INPUT':selectLayer,\
            'PREDICATE':[0],\
            'INTERSECT':QgsProcessingFeatureSourceDefinition(intersectLayer.name(), selectedFeaturesOnly=True),\
            'METHOD':0\
            })


    def start(self):
        selectLayer = QgsProject.instance().mapLayersByName('〇〇')[0]
        intersectLayer = QgsProject.instance().mapLayersByName('〇〇')[0]

        self.intersectSelect2(selectLayer, intersectLayer)
~略~

インストールした状態では、intersectselect_sample.pyの62行目(上のコードでは16行目)が「self.intersectSelect1」になっているので、「self.intersectSelect2」に変更すると、「場所による選択」をプラグインで実行するメソッドが呼ばれます。


ここではprocessingのselectbylocationというアルゴリズムを使いました。その他どのようなアルゴリズムがあるのか調べたい場合は、pythonコンソールで以下のコードを入力してください。

from qgis import processing
for algorithm in QgsApplication.processingRegistry().algorithms():
        print(algorithm.id() + "@" + algorithm.displayName())

また、アルゴリズムの詳細な使い方は、pythonコンソールで以下のコードを入力すれば表示することができます。

processing.algorithmHelp("アルゴリズム名")

参考にしたサイト

stackoverflow.com

gis.stackexchange.com


最後までご覧頂き、ありがとうございました