DotSpatialを使ってシェープファイルの情報を読み取る記事はいくつか書いてきたところですが、データ数が多いと、シェープファイルを開くところで例外(System.OutOfMemoryException)が発生してしまい、処理が止まってしまう事が散発しております。GC.Collectなどをしてもダメな時はダメなので他のライブラリを探していたところ「SharpMap」を見つけました。
ということで、「SharpMap」を使って、シェープファイルの情報(構成点の座標、属性テーブルの内容)を読み取ることが出来たので、備忘録的に記事を残しておきます。
画面上にシェープファイルの情報を表示させるのなら既製のデスクトップGISを使えば良いのですが、大量のシェープファイルから必要な情報だけを抜き出す&QGIS+Pythonの開発環境が無く既に環境が整っているC#(.Net)で作成するのが目的です。
まず、SharpMapを使えるようにするのは非常に簡単で、NuGetのパッケージマネージャからインストールしても良いですし、下記の方法で公式サイトからダウンロードして参照を追加しても良いでしょう。
<公式サイトからダウンロードする場合>
1. 公式サイト右側に大きくある「download」から”SharpMap.zip”をダウンロード
2. “SharpMap.zip”を適当適切なディレクトリに解凍
3. VisualStudioにて「参照の追加」から、2で解凍した”SharpMap.dll”と”GeoAPI.dll”を追加する
処理の流れは
1. ShapeFileクラス(SharpMap.Data.Providers名前空間)でシェープファイルを開く
2. ShapeFileクラスのGetFeatureメソッドで地物をFeatureDataRowに読み込む
3. FeatureDataRowから地物の構成点(FeatureDataRow.Geometry.Coordinate)やデータを読む
といった感じの流れになります。
実際の処理は↓のサンプルにあるとおりです、構成点の座標を読み取っていく方法は、ラインもポリゴンも同じ方法で行けるようです。
あと、今回の目的では画面に図形を表示させる必要は無いのですが、Map(SharpMap名前空間)のインスタンスを発生させておかないとSystem.InvalidOperationException「Cannot use GeometryServiceProvider without an assigned IGeometryServices class」が発生してしまいます。そのため、Mapクラスのインスタンスを発生させております(18行目)。
//冒頭にはこれが書いてある前提です
using SharpMap;
using SharpMap.Layers;
using SharpMap.Data;
using SharpMap.Data.Providers;
using GeoAPI.Geometries;
//中略
//ここから本番処理
//定数
const string sBase = @"D:\hogehoge";
//文字コード変換用
Encoding enc = Encoding.GetEncoding(932);
//地図
Map mp = new Map(); //これが無いとエラーになる
//ポイントデータ
string sShp = Path.Combine(sBase, "point.shp"); //シェープファイル
string sCsv = Path.Combine(sBase, "point.csv"); //情報を格納するcsvファイル
using (StreamWriter sw = new StreamWriter(sCsv, false, enc))
using (ShapeFile sf = new ShapeFile(sShp)) //SharpMap.Data.Providers.ShapeFile
{
sw.WriteLine("x,y,Name");
sf.Encoding = enc; //これを設定しないと文字化けする
for (uint i = 0; i < sf.GetFeatureCount(); i++)
{
//SharpMap.Data.FeatureDataRow
//System.Data.DataRowに座標情報とかが付いたような感じ
FeatureDataRow fdr = sf.GetFeature(i);
string sLine = fdr.Geometry.Coordinate.X.ToString("0.0")
+ "," + fdr.Geometry.Coordinate.Y.ToString("0.0")
+ "," + fdr["Name"];
sw.WriteLine(sLine);
}
}
//ラインデータ
sShp = Path.Combine(sBase, "line.shp");
sCsv = Path.Combine(sBase, "line.csv");
using (StreamWriter sw = new StreamWriter(sCsv, false, enc))
using (ShapeFile sf = new ShapeFile(sShp))
{
sw.WriteLine("x,y,Name");
sf.Encoding = enc;
for (uint i = 0; i < sf.GetFeatureCount(); i++)
{
FeatureDataRow fdr = sf.GetFeature(i);
System.Data.DataRow dr = fdr;
for (int j = 0; j < fdr.Geometry.Coordinates.Length; j++)
{
string sLine = fdr.Geometry.Coordinates[j].X.ToString("0.0")
+ "," + fdr.Geometry.Coordinates[j].Y.ToString("0.0")
+ "," + fdr["Name"];
sw.WriteLine(sLine);
}
}
}
//ポリゴンデータ
sShp = Path.Combine(sBase, "polygon.shp");
sCsv = Path.Combine(sBase, "polygon.csv");
using (StreamWriter sw = new StreamWriter(sCsv, false, enc))
using (ShapeFile sf = new ShapeFile(sShp))
{
sw.WriteLine("x,y,Name");
sf.Encoding = enc;
for (uint i = 0; i < sf.GetFeatureCount(); i++)
{
FeatureDataRow fdr = sf.GetFeature(i);
for (int j = 0; j < fdr.Geometry.Coordinates.Length; j++)
{
string sLine = fdr.Geometry.Coordinates[j].X.ToString("0.0")
+ "," + fdr.Geometry.Coordinates[j].Y.ToString("0.0")
+ "," + fdr["Name"];
sw.WriteLine(sLine);
}
}
}
2016/1/12追記
ShapeFileクラス(SharpMap.Data.Providers名前空間)にEncordingというプロパティ(System.Text.Encoding)があり、これを適切に設定することにより全角文字等の文字化けを回避できます。
参考にさせて頂いたサイト
・C#とSharpMapで地図を描画するアプリケーションを作る
・シェープマップを使う(SharpMap)・新しいバージョン