QGISのプラグイン作成 ラスタから値を補間して取得するサンプル
はじめに
このプラグインのサンプルでは、DEMのラスタから標高値を補完して取得するサンプルです。
使い方
ここからzipファイルをダウンロードしてインストールします。
ラスタレイヤをアクティブにした状態でプラグインを実行すると、マウスカーソル位置の標高をPythonコンソールに表示します。
コード
class GetRasterPixelValueSample(QgsMapTool): def canvasMoveEvent(self, event): print(str(self.gr.getValueInterpolation(self.toMapCoordinates(event.pos())))) def start(self): self.gr = GetRasterPixelValueClass(self.iface.activeLayer()) ~略~ class GetRasterPixelValueClass: def __init__(self, layer: QgsRasterLayer): self.__grs80 = pyproj.Geod(ellps='GRS80') # ピクセル1つのサイズ self.__unitX = layer.rasterUnitsPerPixelX() self.__unitY = layer.rasterUnitsPerPixelY() # ラスタのサイズ self.__height = layer.height() self.__width = layer.width() # ラスタの原点 self.__provider = layer.dataProvider() self.__extent = self.__provider.extent() self.__orgX = self.__extent.xMinimum() self.__orgY = self.__extent.yMaximum() # ピクセル self.block = self.__provider.block(1, self.__extent, self.__width, self.__height) def getIndex(self, pos: QgsPointXY): pixelIdxX = (pos.x() - self.__orgX) / self.__unitX pixelIdxY = (self.__orgY - pos.y()) / self.__unitY if (pixelIdxX < 0) or (pixelIdxY < 0): return None pixelIdxX = int(pixelIdxX) pixelIdxY = int(pixelIdxY) if (pixelIdxX > self.__width - 1) or (pixelIdxY > self.__height - 1): return None return [pixelIdxX, pixelIdxY] def getGeometry(self, idxX: int, idxY: int): if (idxX < 0) or (idxY < 0): return None if (idxX > self.__width - 1) or (idxY > self.__height - 1): return None pixelPosX = self.__unitX * idxX + self.__orgX + self.__unitX / 2 pixelPosY = self.__orgY - self.__unitY * idxY - self.__unitY / 2 return [pixelPosX, pixelPosY] def getValueFromPos(self, pos: QgsPointXY): ident = self.__provider.identify(pos, QgsRaster.IdentifyFormatValue ) if ident.isValid(): return list(ident.results().values())[0] else: return None def getValueFromIdx(self, idxX: int, idxY: int): if (idxX < 0) or (idxY < 0): return None if (idxX > self.__width - 1) or (idxY > self.__height - 1): return None return self.block.value(idxY, idxX) def getValueInterpolation(self, pos: QgsPointXY): pixidx = self.getIndex(pos) if pixidx == None: return None pixelIdxX = pixidx[0] pixelIdxY = pixidx[1] pixpos = self.getGeometry(pixelIdxX, pixelIdxY) pixelPosX = pixpos[0] pixelPosY = pixpos[1] # 右上 if (pixelPosX < pos.x()) and (pixelPosY < pos.y()): if (pixelIdxX > self.__width - 2) or (pixelIdxY - 1 < 0): return None a = self.__getXYZ__(pixelIdxX+1, pixelIdxY-1) b = self.__getXYZ__(pixelIdxX, pixelIdxY-1) c = self.__getXYZ__(pixelIdxX, pixelIdxY) d = self.__getXYZ__(pixelIdxX+1, pixelIdxY) # 左上 elif (pixelPosX >= pos.x()) and (pixelPosY < pos.y()): if (pixelIdxX - 1 < 0) or (pixelIdxY - 1 < 0): return None a = self.__getXYZ__(pixelIdxX, pixelIdxY-1) b = self.__getXYZ__(pixelIdxX-1, pixelIdxY-1) c = self.__getXYZ__(pixelIdxX-1, pixelIdxY) d = self.__getXYZ__(pixelIdxX, pixelIdxY) # 左下 elif (pixelPosX >= pos.x()) and (pixelPosY >= pos.y()): if (pixelIdxX - 1 < 0) or (pixelIdxY > self.__height - 2): return None a = self.__getXYZ__(pixelIdxX, pixelIdxY) b = self.__getXYZ__(pixelIdxX-1, pixelIdxY) c = self.__getXYZ__(pixelIdxX-1, pixelIdxY+1) d = self.__getXYZ__(pixelIdxX, pixelIdxY+1) # 右下 elif (pixelPosX < pos.x()) and (pixelPosY >= pos.y()): if (pixelIdxX > self.__width - 2) or (pixelIdxY > self.__height - 2): return None a = self.__getXYZ__(pixelIdxX+1, pixelIdxY) b = self.__getXYZ__(pixelIdxX, pixelIdxY) c = self.__getXYZ__(pixelIdxX, pixelIdxY+1) d = self.__getXYZ__(pixelIdxX+1, pixelIdxY+1) dist1 = self.__grs80.inv(b.x(), b.y(), a.x(), a.y())[2] dist2 = self.__grs80.inv(b.x(), b.y(), pos.x(), b.y())[2] delta = (a.z() - b.z()) / dist1 tmp1 = delta * dist2 + b.z() dist1 = self.__grs80.inv(c.x(), c.y(), d.x(), d.y())[2] dist2 = self.__grs80.inv(c.x(), c.y(), pos.x(), c.y())[2] delta = (d.z() - c.z()) / dist1 tmp2 = delta * dist2 + c.z() dist1 = self.__grs80.inv(d.x(), d.y(), a.x(), a.y())[2] dist2 = self.__grs80.inv(d.x(), d.y(), d.x(), pos.y())[2] delta = (tmp1 - tmp2) / dist1 inp = delta * dist2 + tmp2 return inp def __getXYZ__(self, idxX: int, idxY: int): x = self.__unitX * idxX + self.__orgX + self.__unitX / 2 y = self.__orgY - self.__unitY * idxY - self.__unitY / 2 z = self.block.value(idxY, idxX) return QgsPoint(x, y, z)
90~121行目 現在の位置の周囲4ピクセルの座標を決めています。コメントで「右上」とある箇所では、現在のピクセルの上、右上、右、現在位置の4ピクセルを取得します。
145行目 その位置のピクセル値をそれぞれ取得します。
123~136行目 補間して、マウス位置の標高値を取得します。
コード全文
最後までご覧いただき、ありがとうございました。
QGISのプラグイン作成 リレーションのサンプル
はじめに
このサンプルは、あるレイヤのレコードに紐付く別のレイヤのレコードを抽出するためのサンプルです。
使い方
ここからzipファイルをダウンロードしてインストールします。
インストールできたら、relation_sample.pyの以下の部分を変更します。
self.referencedLayerName = '〇〇〇' # 被参照のレイヤ名 self.referencingLayerName = '□□□' # 参照元のレイヤ名 self.referencedField = '△△△' # 参照元とのリンクに使うフィールド名 self.referencingField = '×××' # 被参照とのリンクに使うフィールド名
プラグインを実行したままで、被参照レイヤの地物を選択すると...
選択した地物とリンクする参照元レイヤの地物が選択状態になり、属性テーブルが表示されます。
プラグイン実行中は、上の画像のようなリレーションが作られています。
コード
class RelationSample(QgsMapTool): def showChildren(self): parent = self.rel.referencedLayer() child = self.rel.referencingLayer() features = parent.selectedFeatures() if len(features) == 0: return child.removeSelection() # クリアしないと、属性テーブルに余計に表示されるから for c in self.rel.getRelatedFeatures(features[0]): child.select(c.id()) selectedlayer = self.iface.activeLayer() # 現在のアクティブレイヤ退避 try: # このプログラム実行中は属性テーブルは選択中のフューチャーしか表示しないように設定する self.oldsetting = QSettings().value('/Qgis/attributeTableBehaviour') QSettings().setValue('/Qgis/attributeTableBehavior', 'ShowSelected') # テーブル表示 self.iface.setActiveLayer(child) self.iface.mainWindow().findChild(QtWidgets.QAction, 'mActionOpenTable' ).trigger() finally: # 設定を戻す self.iface.setActiveLayer(selectedlayer) QSettings().setValue('/Qgis/attributeTableBehavior', self.oldsetting) def start(self): self.referencedLayer = QgsProject.instance().mapLayersByName(self.referencedLayerName)[0] self.referencingLayer = QgsProject.instance().mapLayersByName(self.referencingLayerName)[0] self.rel = QgsRelation() self.rel.setReferencingLayer(self.referencingLayer.id()) self.rel.setReferencedLayer(self.referencedLayer.id()) self.rel.addFieldPair(self.referencingField, self.referencedField) self.rel.setId('適当なID') self.rel.setName('適当な名前') QgsProject.instance().relationManager().addRelation(self.rel) self.referencedLayer.selectionChanged.connect(self.showChildren) def finish(self): QgsProject.instance().relationManager().removeRelation(self.rel) self.referencedLayer.selectionChanged.disconnect(self.showChildren) def __init__(self, iface): ~略~ self.referencedLayerName = '〇〇〇' # 被参照のレイヤ名 self.referencingLayerName = '□□□' # 参照元のレイヤ名 self.referencedField = '△△△' # 参照元とのリンクに使うフィールド名 self.referencingField = '×××' # 被参照とのリンクに使うフィールド名
32~38行目 リレーションを作成します。
39行目 作成したリレーションを現在のプロジェクトに登録します。
41行目 被参照レイヤの地物を選択したときに呼ばれるメソッドを登録します。
12行目 選択した地物とリンクする参照元レイヤのレコードを選択状態にします。
18~22行目 テーブル設定を、選択地物だけしか表示できないように設定して、被参照レイヤをテーブル表示します。
45行目 プラグインが終了したら、リレーションを削除します。
コード全文
最後までご覧いただき、ありがとうございました。
QGISのプラグイン作成 LayerTreeViewのサンプル
はじめに
このサンプルは、ツリービューからレイヤを選択してアクティブにした時に、そのことをPythonコンソールに表示します。
使い方
ここからzipファイルをダウンロードしてインストールします。
プラグイン実行中に、レイヤウィンドウでレイヤを選択すると...
選択されていたレイヤ名と、現在選択されているレイヤ名がPythonコンソールに表示されます。
コード
class LayerTreeViewSample(QgsMapTool): def changeLayer(self, layer): if (layer == None): # レイヤウィンドウに何も無い状態 self.currentlayer = None self.cleared.emit() return if self.currentlayer != None: print(self.currentlayer.name() + 'が非アクティブになりました。') print(layer.name()+'がアクティブになりました。') self.currentlayer = layer def start(self): self.currentlayer = self.iface.layerTreeView().currentLayer() self.iface.layerTreeView().currentLayerChanged.connect(self.changeLayer) ~略~ def finish(self): self.iface.layerTreeView().currentLayerChanged.disconnect(self.changeLayer) ~略~
18行目 現在アクティブなレイヤ名を取得しておきます。
11行目 ツリービューのアクティブレイヤが変わったら、アクティブだったレイヤ名を表示して...
13行目 アクティブになったレイヤ名を表示させます。
コード全文
最後までご覧いただき、ありがとうございました。