CADとGISをつなぐ ── LibreDWG × GDALでDWGをQGIS / ArcGIS Pro対応GeoPackageへ変換する【v0.3.4 改訂版】
はじめに
AutoCADのDWGを、そのままGISで使いたいことは結構あります。
河川図、道路図、施設台帳、測量図、等高線など、元データはCADで管理されているけれど、解析や地図表示はQGISやArcGIS Proで行いたい。そんな場面は少なくありません。
そこで、GNU LibreDWGとGDALを組み合わせて、DWGをGeoPackageへ変換するDocker環境を作ってきました。
最初の公開版では、
DWG
↓
DXF
↓
GDAL
↓
GeoPackage
という流れが中心でした。
その後、実際の業務DWGで検証を続けると、
- DWG→DXFの段階で形状が正しいか確認したい
- ArcGIS ProでDXFそのものも確認したい
- CAD側はmm、GIS側はmというデータがある
- DXFの座標は変更したくない
- GeoPackageではEPSGをきちんと付けたい
- Polygonの不正geometryを無理に成功扱いしたくない
といった要件が見えてきました。
そこでv0.3.4では、処理の役割を明確に分けています。
v0.3.4で何が変わったか
現在の処理は次のようになっています。
一番大きな変更点は、DXFとGeoPackageの役割を分けたことです。
DXFはCAD側の確認用なので、元のCAD座標をそのまま保持します。
GeoPackageはGIS側で使うため、必要な倍率を適用して、指定したEPSGを付与します。
今回のようにCAD座標がmm、GIS座標がmの場合は、
DXF : 元座標のまま
GeoPackage : XY × 0.001
です。
v0.3.4の成果物
入力DWGが、
河川網図.DWG
なら、正常終了時には同じベース名で次の4ファイルを作ります。
河川網図.dxf
河川網図.prj
河川網図.wld
河川網図.gpkg
v0.3.4では、これを基本成果物としています。
以前のように「DXFが必要な場合だけ --dxf を付ける」という考え方ではありません。
DWG→DXFの変換結果を確認できること自体が重要なので、DXFは必ず残します。
DXFはスケール変換しない
ここはv0.3.4でかなり重要な部分です。
例えば元DWGの座標が、
X = -64,000,000
Y = -130,000,000
だったとします。
この値がmm座標なら、GISでは、
X = -64,000 m
Y = -130,000 m
として使いたいところです。
ただし、DXFそのものを書き換えてしまうと、
DWG→DXF変換が正しかったのか
GIS用のスケール変換で変わったのか
が分からなくなります。
そこでDXFは、
X = -64,000,000
Y = -130,000,000
のまま保存します。
--scale-to-m はDXFには適用しません。
ArcGIS ProではPRJ + WLDを使う
DXFをArcGIS Proで正しい位置に表示するため、v0.3.4ではDXFと一緒に .prj と .wld を生成します。
例えば、
--epsg=6676
を指定すると、
JGD2011 / Japan Plane Rectangular CS VIII
としてPRJを作ります。
EPSG:6676はJGD2011 / 平面直角座標系VIII系で、単位はmetreです。
WLDは今回のmm→m運用に合わせて、次の固定値です。
0.0,0.0 0.0,0.0
1000.0,0.0 1.0,0.0
意味は、
CAD座標 GIS座標
0 → 0
1000 mm → 1 m
です。
つまり、
scale = 0.001
rotation = 0
translation = 0,0
になります。
ArcGIS Proでは、
河川網図.dxf
河川網図.prj
河川網図.wld
を同じディレクトリに置いて読み込みます。
DXF自体は変更していませんが、ArcGIS Pro側ではWLDによって1/1000の位置に表示されます。
Esriのドキュメントでも、CADと同名のWLDを使ってoffset / scale / rotationを与える仕組みが説明されています。
GeoPackageは0.001倍して保存する
GeoPackage側は逆に、GISでそのまま使える座標として保存します。
今回の標準設定は、
--scale-to-m=0.001
です。
つまり、
GeoPackage座標 = DXF座標 × 0.001
です。
例えば、
DXF
X = -64,000,000
GeoPackage
X = -64,000
となります。
さらに、
--epsg=6676
を指定していれば、GeoPackage側にはEPSG:6676を設定します。
そのため、
DXF + PRJ + WLD
と、
GeoPackage
をArcGIS Proへ同時に追加すると、同じ位置に重なるのが正しい結果です。
v0.3.4の基本的な使い方
1. ZIPを展開する
下記よりダウンロードして下さい。
https://godo-tys.jp/downloads/dwg2geopackage_v0.3.4.zip
unzip dwg2geopackage_v0.3.4.zip
cd dwg2geopackage_v0.3.4
chmod +x ./scripts/*.sh
ホスト側で必要なのは基本的に、
Docker
Docker Compose v2
です。
LibreDWG、GDAL、Python側の処理はDockerイメージ内に入れています。
2. まずDocker環境を検証する
最初に、
./scripts/verify_docker.sh
を実行します。
v0.3.4では、単なるPythonのunit testだけではなく、
Docker Compose設定
↓
LibreDWG build
↓
LibreDWG version / commit確認
↓
pytest
↓
実GDAL DXF→GeoPackage
↓
EPSG確認
↓
scale確認
↓
DXF / PRJ / WLD / GPKG確認
まで確認する構成にしています。
LibreDWGはnightlyの、
0.14.8597
short commit: 34f02f5
を固定しています。
CAD変換ツールはライブラリ側の更新によって結果が変わる可能性があるため、
どのLibreDWGで変換したか
を追えるようにしています。
3. 実DWGを変換する
JGD2011 / 平面直角座標系VIII系、CAD単位mmの場合は次のように実行します。
./scripts/dwg2geopackage.sh \
"/home/tys/dwg/input/河川図.DWG" \
"/home/tys/dwg/output" \
--epsg=6676 \
--scale-to-m=0.001
正常終了すると、
/home/tys/dwg/output/
├── 河川図.dxf
├── 河川図.prj
├── 河川図.wld
├── 河川図.gpkg
└── logs/
となります。
ファイル名を個別指定しなくても、元DWGと同じベース名で出力します。
--epsg は座標系を指定する
今回は、
--epsg=6676
を使っています。
これは、
JGD2011 / Japan Plane Rectangular CS VIII
JGD2011 / 平面直角座標系VIII系
です。
国内の別の平面直角座標系を使う場合も、対象となるEPSGを指定します。
例えばJGD2011の平面直角座標系はEPSGコードが系ごとに分かれています。
重要なのは、
CAD座標値の意味
EPSG
単位
を混同しないことです。
--epsg は座標参照系を指定します。
--scale-to-m はCAD座標値をmetreへ変換する倍率です。
別の役割です。
Python主体の構成へ変更した
初期版ではShellとogr2ogrを中心に処理していました。
v0.3.xからは、変換ロジックをPythonへ移しています。
構成はおおよそ次のようになっています。
src/dwg2geopackage/
├── cli.py
├── dwg.py
├── libredwg.py
├── dxf.py
├── geopackage.py
├── pipeline.py
├── process.py
├── compare.py
└── errors.py
役割は、
dwg.py
DWG version判定
libredwg.py
LibreDWG実行
DWG→DXF
dxf.py
DXF header確認
coordinate診断
GDAL preflight
geopackage.py
DXF→GeoPackage
geometry分類
scale適用
EPSG設定
pipeline.py
全工程の実行制御
manifest生成
という形です。
Shell scriptは、
Dockerを起動する
Python CLIへ引数を渡す
程度の薄いラッパーにしています。
これで問題が起きたときに、
DWG読取りで失敗
DXF生成で失敗
DXF診断で失敗
GeoPackage生成で失敗
最終検証で失敗
を切り分けやすくなりました。
DWGと同じ世代のDXFを作る
DWGの先頭からバージョンを確認し、同世代のDXFへ変換します。
例えば、
AC1032
なら、
R2018 DWG
↓
R2018 DXF
です。
対応関係は次のように扱っています。
AC1014 -> R14
AC1015 -> R2000
AC1018 -> R2004
AC1021 -> R2007
AC1024 -> R2010
AC1027 -> R2013
AC1032 -> R2018
LibreDWGのdwg2dxfには--as r2018などの出力バージョン指定があります。
v0.3.4では、理由なく別世代へ落とすfallbackは使わず、元DWGと同じ世代を基本にしています。
DXFを先に診断する
以前は、
DWG
↓
GeoPackage
の結果だけを見ていました。
ただ、実データでLineやPolygonの形状に違和感が出たとき、
DWG自体がおかしいのか
LibreDWGでDXFへ変換した時点でおかしいのか
DXF→GeoPackageでおかしくなったのか
を分けられませんでした。
そこで現在は、
DWG
↓
DXF
↓
DXFを確認
↓
問題がなければGeoPackage
という考え方にしています。
DXF診断では、entity typeごとに、
entity count
coordinate count
extent
non-finite coordinate
極端に大きな座標
などを確認します。
ArcGIS ProでDXFそのものを表示できるようPRJ / WLDも一緒に作るので、GeoPackageへ進む前の確認がかなり楽になりました。
DXFが書き換わっていないことも確認する
v0.3.4では、GeoPackageを作る前後でDXFのSHA-256を比較します。
DXF生成
↓
SHA-256
↓
GeoPackage生成
↓
DXFのSHA-256を再計算
↓
一致確認
一致しなければエラーです。
これは、
GeoPackageを作るためにDXFを加工してしまった
という状態を防ぐためです。
DXFはあくまでLibreDWGから出したCAD側の確認用成果物として残します。
GeoPackageはgeometry typeごとに分ける
GDALのDXF Readerから読み込んだgeometryを、そのまま1つの混在レイヤへ入れるのではなく、GeoPackageでは分離します。
entities_point
entities_multipoint
entities_line
entities_polygon
Multipointがなければ空レイヤは作りません。
ArcGIS ProではPoint / Line / Polygonがfeature classとして分かれている方が扱いやすいためです。
属性についても、DXFから取得できる、
Layer
SubClasses
EntityHandle
Text
などを可能な範囲で保持します。
追跡用として、
source_fid
cad_style
なども追加しています。
Polygonを無理に成功扱いしない
CADのHATCHなどは、CAD上では見た目が正常でも、GIS Polygonとしては不正になることがあります。
例えば、
Self-intersection
Hole lies outside shell
Too few points
といったケースです。
Polygon候補は必要に応じてMakeValid()を使います。
それでもGIS Polygonとして成立しないものは、無理にgeometryとして保存せず、rejectedとして扱います。
つまり、
変換コマンドが最後まで動いた
だけで成功とは判断しません。
GeoPackage生成後も検証する
v0.3.4では一時GeoPackageへ書き込み、検証後に最終ファイルとして公開します。
DXF
↓
.tmp.gpkg
↓
検証
├─ FAIL -> tmpを削除
└─ PASS -> 正式な .gpkg へ置換
確認している主な内容は、
SQLite integrity_check
EPSG
Feature count
Layer count
Extent
finite coordinate
geometry type
です。
正常な既存GeoPackageがある場合、新しい変換が失敗したからといって先に消さないようにしています。
現在残っている注意点
実DWGでは、いくつか警告が出る場合があります。
CP932 / UTF-8
一部のDWG / DXFでは、
One or several characters couldn't be converted correctly
from CP932 to UTF-8
が出ることがあります。
Geometryそのものとは別ですが、日本語TEXTやLayer名などの属性文字列については引き続き確認が必要です。
3Dと2D
Sub-geometry ... coordinate dimension 3,
but container has 2
という警告が出ることがあります。
平面GISとしてXYだけを使うデータでは大きな問題にならない場合がありますが、Zを必要とする用途では別途扱いを決める必要があります。
CAD PolygonとGIS Polygonは同じではない
CAD上で正常に見えるHATCHでも、GIS Polygonとしては、
Self-intersection
Hole lies outside shell
Too few points
になる場合があります。
このため、v0.3.4ではrejectedを成功件数へ混ぜないようにしています。
このツールの役割
このツールは、
AutoCADの図面を完全に再現するCADエンジン
を目指しているわけではありません。
目的は、
DWG
↓
CADとして確認可能なDXF
+
GISで使えるGeoPackage
を再現可能なDocker環境で作ることです。
最終的には、
DWG受領
↓
DWG→DXF
↓
ArcGIS ProでDXF確認
↓
GeoPackage
↓
PostGIS
↓
WebGIS
という流れにつなげたいと考えています。
CADデータを毎回手作業でGIS形式へ変換する部分を自動化できれば、その後のWebGISや空間解析へかなりつなげやすくなります。
今回の改訂で変わった考え方
初期版では、
DWGをGeoPackageへ変換できるか
が中心でした。
v0.3.4では少し考え方が変わっています。
DWG
↓
DXFという確認可能な中間成果物を残す
↓
ArcGIS Proでも確認できるようPRJ / WLDを付ける
↓
同じDXFからGeoPackageを作る
↓
座標・geometry・件数を検証する
です。
これなら、GeoPackageがおかしかったときにも、
DWG→DXFの問題
DXF→GISの問題
元CADデータの問題
を切り分けやすくなります。
実データを扱うツールでは、単に「変換できた」より、こちらの方が重要だと思っています。
まとめ
v0.3.4では、DWGから次の4ファイルを標準成果物として出力するようになりました。
input.dwg
↓
input.dxf
input.prj
input.wld
input.gpkg
役割は、
DXF
CAD座標のまま
PRJ
--epsgで指定した座標参照系
WLD
ArcGIS Pro用の1/1000変換
GeoPackage
--scale-to-m=0.001を適用
EPSGを設定
です。
今回のJGD2011 / 平面直角座標系VIII系なら、
./scripts/dwg2geopackage.sh \
input.DWG \
output \
--epsg=6676 \
--scale-to-m=0.001
で使えます。
DWGからGISデータを作る処理は、変換部分だけを見ると簡単そうですが、実際には、
DWG世代
DXF
文字コード
単位
座標系
CAD geometry
GIS geometry
ArcGIS互換性
検証
を一つずつ分けて考えた方が安定します。
v0.3.4で、ようやくその役割分担がかなり整理できました。
次はこのGeoPackageをPostGISへ登録し、OpenLayersから表示できるところまでつなげていく予定です。
参考
-
GNU LibreDWG
https://www.gnu.org/software/libredwg/ -
LibreDWG
dwg2dxf
https://github.com/LibreDWG/libredwg/blob/master/programs/dwg2dxf.1 -
LibreDWG GitHub mirror
https://github.com/LibreDWG/libredwg -
GDAL DXF driver
https://gdal.org/en/stable/drivers/vector/dxf.html -
GDAL GeoPackage driver
https://gdal.org/en/stable/drivers/vector/gpkg.html -
ArcGIS Pro - CAD geospatial coordinates
https://doc.esri.com/en/arcgis-pro/latest/help/data/cad/about-cad-coordinate-systems.html -
ArcGIS Pro - World files for CAD data
https://pro.arcgis.com/en/pro-app/latest/help/data/cad/world-files-for-cad-data.htm -
EPSG:6676 - JGD2011 / Japan Plane Rectangular CS VIII
https://epsg.io/6676 -
旧記事 / 改訂元
https://qiita.com/rino_yume/items/dad684526717a806fec8
