1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PLATEAU QGIS Pluginでフォルダ内のGMLファイルをすべてレイヤに追加する

Posted at

はじめに

QGISでPLATEAUのCityGMLを読み込むには様々な方法があります。
たとえば、CityGMLのgmlファイルをQGISにドラッグ&ドロップしてもレイヤに追加することができますが、LOD2があるファイルはLOD2の部分を読み込むことができません。
もう一つの方法が「PLATEAU QGIS Plugin」で読み込む方法です。
しかし、PLATEAU QGIS Pluginは、1度の実行でファイル一つしか読み込むことができません
そこで、PLATEAU QGIS Pluginを使って、同じフォルダ内のCityGMLファイル(gmlファイル)を一括で読み込んで、QGISのレイヤに追加するPythonスクリプトを作成しました。

PLATEAU GML Pluginのインストール

あらかじめQGISに「PLATEAU GML Plugin」をインストールしておいてください。
プラグインのインストールは次のページを参照しましょう。
プラグインでQGISをもっと便利に〜概要とインストール方法〜(QGIS LAB)

一括読み込みのPythonスクリプト

フォルダ内のCityGMLファイルを一括で読み込んでQGISのレイヤに追加するPythonスクリプトは次のとおりです。

PLATEAU_GML2QGIS.py
"""
Model exported as python.
Name : 都市モデル読込(フォルダ内一括)
Group : PLATEAU処理
With QGIS : 34400
"""

#このスクリプトはPLATEAU QGIS Pluginを使って、フォルダ内のすべてのgmlファイルを一括でレイヤに追加します。
#プロセシングツールボックスのスクリプト→「ツールボックスにスクリプトを追加」でツールボックスに追加できます。

import os
from typing import Any, Optional

from qgis.core import (
    QgsProcessing,
    QgsProcessingAlgorithm,
    QgsProcessingContext,
    QgsProcessingFeedback,
    QgsProcessingMultiStepFeedback,
    QgsProcessingParameterFile,
    QgsProcessingParameterCrs,
    QgsCoordinateReferenceSystem,
    QgsProcessingException
)
from qgis import processing


class LoadCityGMLFolderAlgorithm(QgsProcessingAlgorithm):

    def initAlgorithm(self, config: Optional[dict[str, Any]] = None):
        # フォルダの選択
        self.addParameter(
            QgsProcessingParameterFile(
                'citygml_folder',
                'cityGMLフォルダ',
                behavior=QgsProcessingParameterFile.Folder,
                defaultValue=None
            )
        )

        # CRSの選択(デフォルトは EPSG:6668)
        self.addParameter(
            QgsProcessingParameterCrs(
                'crs',
                '座標参照系(CRS)',
                defaultValue='EPSG:6697'
            )
        )

    def processAlgorithm(self, parameters: dict[str, Any], context: QgsProcessingContext, model_feedback: QgsProcessingFeedback) -> dict[str, Any]:
        folder_path = parameters['citygml_folder']
        crs = parameters['crs']  # 選択されたCRS

        # GMLファイル一覧を取得
        gml_files = [f for f in os.listdir(folder_path) if f.lower().endswith('.gml')]
        total = len(gml_files)

        if total == 0:
            raise QgsProcessingException('指定フォルダにGMLファイルが見つかりません。')

        feedback = QgsProcessingMultiStepFeedback(total, model_feedback)
        results = {}
        outputs = {}

        for index, gml_file in enumerate(sorted(gml_files)):
            feedback.setCurrentStep(index)
            if feedback.isCanceled():
                break

            input_path = os.path.join(folder_path, gml_file)
            feedback.pushInfo(f"{index+1}/{total} ファイルを処理中: {gml_file}")

            alg_params = {
                'APPEND_MODE': True,
                'CRS': crs,
                'FORCE_2D': False,
                'INPUT': input_path,
                'LOD_PREFERENCE': 2, #すべてのLODを読み込む 
                'SEMANTIC_PARTS': True
            }

            result = processing.run(
                'plateau_plugin:load_as_vector',
                alg_params,
                context=context,
                feedback=feedback,
                is_child_algorithm=True
            )
            outputs[gml_file] = result

        return results

    def name(self) -> str:
        return 'loadcitygmlfolder'

    def displayName(self) -> str:
        return '都市モデル読込(フォルダ内一括)'

    def group(self) -> str:
        return 'PLATEAU処理'

    def groupId(self) -> str:
        return 'plateau'

    def createInstance(self):
        return LoadCityGMLFolderAlgorithm()

スクリプトをプロセシングツールボックスに追加

上記のコードをテキストエディタなどにコピーして、「PLATEAU_GML2QGIS.py」というファイル名で保存します。
QGISを起動して、

  1. メニュー「プロセシング」→「ツールボックス」を選択して、プロセシングツールボックスパネルを表示します。
    image.png

  2. スクリプトボタンをクリックして、「ツールボックスにスクリプトを追加」を選択し、「PLATEAU_GML2QGIS.py」を選択します。
    image.png

  3. プロセシングツールボックスに、「スクリプト」→「PLATEAU処理」→「都市モデル読込(フォルダ内一括)」というメニューが追加されます。
    image.png

CityGMLファイルの一括処理

「都市モデル読込(フォルダ内一括)」を実行し、CityGMLが保存されているフォルダを指定して、座標参照系も選択し、「実行」ボタンをクリックすると、gmlファイルを一括読込して、レイヤに追加します。
image.png


同名のレイヤをマージするスクリプト

上記のコードでQGISにレイヤを追加すると、同じ種類のレイヤは同じ名前でレイヤに追加されます。例えば建物LOD1は「Building (LoD1)」という名前で複数のレイヤが追加されます。
そこで、次のスクリプトを実行すると、同じ名前のレイヤを一つのレイヤにマージできます。元のレイヤは削除されます。
スクリプトは、上記のスクリプトと同じように、プロセシングツールボックスのスクリプトボタンをクリックして、「ツールボックスにスクリプトを追加」を選択し、Pythonファイルを選択します。

MergeLayers.py
"""
Model exported as python.
Name : 同名レイヤのマージと削除
Group : PLATEAU処理
With QGIS : 34400
"""

#このスクリプトは、プロセシングツールボックスのスクリプト→「ツールボックスにスクリプトを追加」でツールボックスに追加できます。
#「都市モデル読込(フォルダ内一括)」を実行後に、同じ名前のレイヤをマージします。
#例えば建物データを読み込むと同じ種類のレイヤは、「Building (LoD1)」などの同じ名前のレイヤ名になります。
#メニューを実行して、同じ種類のレイヤを一つのレイヤにマージします。

from qgis.core import (
    QgsProcessing,
    QgsProcessingAlgorithm,
    QgsProcessingContext,
    QgsProcessingFeedback,
    QgsProcessingException,
    QgsProject,
    QgsVectorLayer
)
import processing

class MergeDuplicateLayersAlgorithm(QgsProcessingAlgorithm):

    def initAlgorithm(self, config=None):
        # パラメータなし(すべての同名レイヤを対象にする)
        pass

    def processAlgorithm(self, parameters, context: QgsProcessingContext, feedback: QgsProcessingFeedback):
        project = QgsProject.instance()
        layers = list(project.mapLayers().values())

        # レイヤ名でグループ化
        layer_dict = {}
        for layer in layers:
            if not isinstance(layer, QgsVectorLayer):
                continue
            name = layer.name()
            if name not in layer_dict:
                layer_dict[name] = []
            layer_dict[name].append(layer)

        merged_count = 0

        for name, same_name_layers in layer_dict.items():
            if len(same_name_layers) < 2:
                continue  # 重複なし

            feedback.pushInfo(f"マージ対象: {name} ({len(same_name_layers)}個)")

            try:
                result = processing.run("native:mergevectorlayers", {
                    'LAYERS': same_name_layers,
                    'CRS': same_name_layers[0].crs().authid(),
                    'OUTPUT': 'memory:' + name + '_merged'
                }, context=context, feedback=feedback)

                merged_layer = result['OUTPUT']
                merged_layer.setName(name)
                project.addMapLayer(merged_layer)

                # 元のレイヤを削除
                for layer in same_name_layers:
                    project.removeMapLayer(layer)

                merged_count += 1

            except Exception as e:
                feedback.reportError(f"{name} のマージに失敗しました: {e}")

        feedback.pushInfo(f"{merged_count} 件の重複レイヤをマージして追加しました。")

        return {}

    def name(self):
        return 'mergeduplicatelayers'

    def displayName(self):
        return '同名レイヤのマージと削除'

    def group(self) -> str:
        return 'PLATEAU処理'

    def groupId(self) -> str:
        return 'plateau'

    def createInstance(self):
        return MergeDuplicateLayersAlgorithm()


実行すると、同名のレイヤをマージします。
image.png

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?