【QGIS】国土地理院ベクターのズーム制限解除 & 巨大点群からの傾斜区分図自動作成(岐阜県バージョン)

【QGIS】国土地理院ベクターのズーム制限解除 & 巨大点群からの傾斜区分図自動作成(岐阜県バージョン)

1. 国土地理院ベクタータイルの「拡大すると消える」問題を解決する

QGISで「国土地理院ベクター(最適化ベクトルタイル)」を表示した際、標準スタイルではズームレベル16.1以上に拡大すると建物や道路が消えてしまう仕様になっています。これでは詳細な図面作成ができません。

ベクタタイルレイヤはプロパティから一括でズームレベルを変更できませんが、Pythonコンソールを使えば一瞬で全項目の制限を解除できます。

【解決手順】

  1. レイヤパネルで「国土地理院ベクター」レイヤを選択。

  2. メニューの [プラグイン][Pythonコンソール] を開く。

  3. 下部の入力欄に以下の1行を貼り付けてEnter。

Python
layer = iface.activeLayer(); styles = layer.renderer().styles(); [s.setMaxZoomLevel(22) for s in styles]; layer.renderer().setStyles(styles); layer.triggerRepaint()

これでレベル22まで拡大しても地物が表示され続けます。


2. 巨大点群から傾斜区分図を一括作成する(岐阜県仕様)

数千万点のデータから傾斜区分図を作る際、QGISのGUI操作ではフリーズのリスクが高まります。ここでは、用途に応じて使い分けられる「超高速版」「高精度フルバージョン」の2つのスクリプトを紹介します。

傾斜区分の定義(5段階)

  • 値 1:0° - 2°(緑色)

  • 値 2:2° - 15°(黄緑色)

  • 値 3:15° - 30°(薄い黄色)

  • 値 4:30° - 45°(山吹色)

  • 値 5:45° - 90°(オレンジ色)


A. 【超高速版】とりあえず全体を素早く確認したい時

1000万点超えのデータでも数分で完了します。微地形は多少簡略化されますが、スピード重視の現場確認に最適です。

Python
import os
import numpy as np
import tkinter as tk
from tkinter import filedialog
try:
    from osgeo import gdal, ogr, osr
except ImportError:
    print("エラー: GDALライブラリが見つかりません。OSGeo4W Shellから実行してください。")
    import sys
    sys.exit()

def process_fast_slope():
    root = tk.Tk()
    root.withdraw()
    root.attributes('-topmost', True)
    input_path = filedialog.askopenfilename(title="処理するファイルを選択", filetypes=[("GeoPackage/Shapefile", "*.gpkg;*.shp")])
    if not input_path: return

    base_dir = os.path.dirname(input_path)
    base_name = os.path.splitext(os.path.basename(input_path))[0]
    output_name = base_name.replace("_clipped", "")

    dem_tif = os.path.join(base_dir, f"{output_name}_dem.tif")
    slope_tif = os.path.join(base_dir, f"{output_name}_slope.tif")
    reclass_tif = os.path.join(base_dir, f"{output_name}_reclass.tif")
    
    z_field = "Z"      
    res = 1.0          

    ds = ogr.Open(input_path)
    layer = ds.GetLayer()
    x_min, x_max, y_min, y_max = layer.GetExtent()
    srs = layer.GetSpatialRef()
    srs_wkt = srs.ExportToWkt() if srs else 'EPSG:6675' 
    
    print(f"超高速処理開始: {os.path.basename(input_path)}")
    
    # 1. ラスタライズ
    gdal.Rasterize(dem_tif, input_path, options=gdal.RasterizeOptions(
        format='GTiff', outputBounds=[x_min, y_min, x_max, y_max],
        xRes=res, yRes=res, attribute=z_field, noData=-9999, outputType=gdal.GDT_Float32, outputSRS=srs_wkt))

    # 2. 隙間補間
    ds_dem = gdal.Open(dem_tif, gdal.GA_Update)
    gdal.FillNodata(targetBand=ds_dem.GetRasterBand(1), maskBand=None, maxSearchDist=20, smoothingIterations=0)
    ds_dem = None

    # 3. 傾斜計算
    gdal.DEMProcessing(slope_tif, dem_tif, 'slope', options=gdal.DEMProcessingOptions(format='GTiff', computeEdges=True, slopeFormat='degree'))

    # 4. 再分類
    ds_slope = gdal.Open(slope_tif)
    band = ds_slope.GetRasterBand(1)
    arr = band.ReadAsArray()
    nodata = band.GetNoDataValue()
    
    reclass = np.full(arr.shape, -9999, dtype=np.int16)
    v = (arr != nodata)
    reclass[v & (arr >= 0) & (arr <= 2)] = 1
    reclass[v & (arr > 2) & (arr <= 15)] = 2
    reclass[v & (arr > 15) & (arr <= 30)] = 3
    reclass[v & (arr > 30) & (arr <= 45)] = 4
    reclass[v & (arr > 45)] = 5

    driver = gdal.GetDriverByName('GTiff')
    ds_out = driver.Create(reclass_tif, ds_slope.RasterXSize, ds_slope.RasterYSize, 1, gdal.GDT_Int16)
    ds_out.SetGeoTransform(ds_slope.GetGeoTransform())
    ds_out.SetProjection(ds_slope.GetProjection())
    ds_out.GetRasterBand(1).WriteArray(reclass)
    ds_out.GetRasterBand(1).SetNoDataValue(-9999)
    ds_out = ds_slope = None
    print(f"✅ 完了: {reclass_tif}")

if __name__ == "__main__":
    process_fast_slope()
input("Enterキーを押して終了...")

B. 【高精度フルバージョン】公式図面・報告書作成用

全ての点を精密に結ぶ「線形補間」を行います。1000万点超えでは10時間以上かかる場合がありますが、微地形まで忠実に再現します。退勤前の実行を推奨します。

Python
import os
import numpy as np
import tkinter as tk
from tkinter import filedialog
try:
    from osgeo import gdal, ogr, osr
except ImportError:
    print("エラー: GDALライブラリが見つかりません。")
    import sys
    sys.exit()

def process_full_slope():
    root = tk.Tk()
    root.withdraw()
    root.attributes('-topmost', True)
    input_path = filedialog.askopenfilename(title="処理するファイルを選択", filetypes=[("GeoPackage/Shapefile", "*.gpkg;*.shp")])
    if not input_path: return

    base_dir = os.path.dirname(input_path)
    base_name = os.path.splitext(os.path.basename(input_path))[0]
    output_name = base_name.replace("_clipped", "")

    dem_tif = os.path.join(base_dir, f"{output_name}_dem.tif")
    slope_tif = os.path.join(base_dir, f"{output_name}_slope.tif")
    reclass_tif = os.path.join(base_dir, f"{output_name}_reclass.tif")
    
    z_field = "Z"      
    res = 1.0          

    ds = ogr.Open(input_path)
    layer = ds.GetLayer()
    x_min, x_max, y_min, y_max = layer.GetExtent()
    width = int((x_max - x_min) / res)
    height = int((y_max - y_min) / res)
    srs = layer.GetSpatialRef()
    srs_wkt = srs.ExportToWkt() if srs else 'EPSG:6675'
    
    print(f"高精度版処理開始: {os.path.basename(input_path)}")
    
    # 1. 線形補間(Grid)
    gdal.Grid(dem_tif, input_path, options=gdal.GridOptions(
        format='GTiff', outputBounds=[x_min, y_min, x_max, y_max],
        width=width, height=height, algorithm='linear', zfield=z_field, outputSRS=srs_wkt))

    # 2. 傾斜計算
    gdal.DEMProcessing(slope_tif, dem_tif, 'slope', options=gdal.DEMProcessingOptions(format='GTiff', computeEdges=True, slopeFormat='degree'))

    # 3. 再分類
    ds_slope = gdal.Open(slope_tif)
    band = ds_slope.GetRasterBand(1)
    arr = band.ReadAsArray()
    nodata = band.GetNoDataValue()
    
    reclass = np.full(arr.shape, -9999, dtype=np.int16)
    v = (arr != nodata)
    reclass[v & (arr >= 0) & (arr <= 2)] = 1
    reclass[v & (arr > 2) & (arr <= 15)] = 2
    reclass[v & (arr > 15) & (arr <= 30)] = 3
    reclass[v & (arr > 30) & (arr <= 45)] = 4
    reclass[v & (arr > 45)] = 5

    driver = gdal.GetDriverByName('GTiff')
    ds_out = driver.Create(reclass_tif, ds_slope.RasterXSize, ds_slope.RasterYSize, 1, gdal.GDT_Int16)
    ds_out.SetGeoTransform(ds_slope.GetGeoTransform())
    ds_out.SetProjection(ds_slope.GetProjection())
    ds_out.GetRasterBand(1).WriteArray(reclass)
    ds_out.GetRasterBand(1).SetNoDataValue(-9999)
    ds_out = ds_slope = None
    print(f"✅ 完了: {reclass_tif}")

if __name__ == "__main__":
    process_full_slope()
input("Enterキーを押して終了...")

おわりに

作成された _reclass.tif をQGISに読み込み、「単バンド疑似カラー」「正確」モードで5色を割り当てれば完成です。

コメント

  1. 建物の色を砂防基盤図に合わせる。
    QColor(170, 5, 134)

    from qgis.PyQt.QtGui import QColor
    from qgis.core import Qgis

    layer = iface.activeLayer()
    styles = layer.renderer().styles()
    pink = QColor(170, 5, 134)

    for s in styles:
    # ここを layerName() に修正しました
    if s.layerName() == 'building':
    sym = s.symbol()
    # 線(LineString)の場合は線の色を変更
    if sym.type() == Qgis.SymbolType.Line:
    sym.setColor(pink)
    # 面(Polygon)の場合は外枠(Stroke)の色を変更
    elif sym.type() == Qgis.SymbolType.Fill:
    sym.symbolLayer(0).setStrokeColor(pink)

    layer.renderer().setStyles(styles)
    layer.triggerRepaint()

    返信削除
  2. ズームレベルを破壊(拡大すると、非表示になる)

    layer = iface.activeLayer(); styles = layer.renderer().styles(); [s.setMaxZoomLevel(22) for s in styles]; layer.renderer().setStyles(styles); layer.triggerRepaint()

    返信削除

コメントを投稿

このブログの人気の投稿

IJCAD(AutoCAD互換CAD) コマンド早見表

設計定数を求めるための代表N値について

日本でよく使う EPSG コード 一覧