[DotSpatial]ポイントがポリゴンに含まれているか判別する②

一つ前の記事の続きです。
シェープファイルに保存されたポイント(点)がポリゴン(面)に含まれるか否かをDotSpatialで判定する時に使った3つの方法での処理時間を比較してみます。

準備したシェープファイル(ポイントとポリゴン)は一つ前の記事と同じくこんな感じで、たとえばAのポリゴンの中には3・5のポイントが含まれています。

キャプチャ

using DotSpatial.Data;
using DotSpatial.Topology;
using DotSpatial.Projections;

/* 中略 */

//読み取るシェープファイル
const string sPolygon = @"C:\hoge\Polygon.shp";
const string sPoint = @"C:\hoge\Point.shp";

//判定結果はテキストファイルへ
const string sOut = @"C:\hoge\Result.txt";

//処理時間計測用
System.Diagnostics.Stopwatch swTime = new System.Diagnostics.Stopwatch();

//シェープファイルを開く・準備する
using(PolygonShapefile psPoly = new PolygonShapefile(sPolygon))
using(PointShapefile psPt = new PointShapefile(sPoint))
using(StreamWriter sw = new StreamWriter(sOut, false, Encoding.UTF8))
{
    //Prjファイル読み取り
    psPoly.ReadProjection();
    psPt.ReadProjection();
    
    //読み取った結果を表示
    Console.WriteLine("Poly :{0}", psPoly.Projection);
    Console.WriteLine("Point:{0}", psPt.Projection);

    //手法①
    //DotSpatial.Topology.Polygon.Contains(Point)
    swTime.Start();
    foreach (Feature fPoly in psPoly.Features)
    {
        Polygon pg = new Polygon(fPoly.Coordinates);
        foreach (Feature fPt in psPt.Features)
        {
            Point pt = new Point(fPt.Coordinates[0]);
            if (pg.Contains(pt)) //重なり判定
            {
                sw.WriteLine("Method1 Polygon:{0} Point:{1}",
                    fPoly.DataRow[0].ToString(),
                    fPt.DataRow[0].ToString());
            }
        }
    }
    Console.WriteLine("Method1:{0}", swTime.ElapsedMilliseconds);

    //手法②
    //DotSpatial.Topology.Polygon.IsWithinDistance(Point, double)
    swTime.Reset();
    swTime.Start();
    foreach (Feature fPoly in psPoly.Features)
    {
        Polygon pg = new Polygon(fPoly.Coordinates);
        foreach (Feature fPt in psPt.Features)
        {
            Point pt = new Point(fPt.Coordinates[0]);
            if (pg.IsWithinDistance(pt, 0)) //重なり判定
            {
                sw.WriteLine("Method2 Polygon:{0} Point:{1}",
                    fPoly.DataRow[0].ToString(),
                    fPt.DataRow[0].ToString());
            }
        }
    }
    Console.WriteLine("Method2:{0}", swTime.ElapsedMilliseconds);

    //手法③
    //DotSpatial.Data.Feature.IsWithinDistance(Feature, double)
    swTime.Reset();
    swTime.Start();
    foreach (Feature fPoly in psPoly.Features)
    {
        foreach (Feature fPt in psPt.Features)
        {
            if (fPoly.IsWithinDistance(fPt, 0)) //重なり判定
            {
                sw.WriteLine("Method3 Polygon:{0} Point:{1}",
                    fPoly.DataRow[0].ToString(),
                    fPt.DataRow[0].ToString());
            }
        }
    }
    Console.WriteLine("Method3:{0}", swTime.ElapsedMilliseconds);
}

まずは、ポイントとシェープファイルの測地系を揃えた状態で実行してみます。
実行結果(標準出力)

コンソールの標準出力1・2行目はコードの23・24行目で読み取ったProjetcitonの内容です。

そして、標準出力3~5行目がポリゴンに内包されるかの判定(コード:)にかかった時間。意外にも手法③のFeature.IsWithinDistance(Feature, double)の処理時間が短く、手法①のPolygon.Contains(Point)が一番時間がかかるという結果になりました。手法①と②はどちらもPolygonクラスを用いているものの、処理時間に10倍近く差があるのでContainsメソッドとIsWithinDistanceメソッドの処理速度の違いでしょう(むしろ後者の方が時間がかかりそうなのですが、不思議です)。

ちなみに出力結果は↓のとおりで、試した3つの手法で同じ結果が得られています。

Method1 Polygon:A Point:3
Method1 Polygon:A Point:5
Method1 Polygon:B Point:4
Method1 Polygon:C Point:6
Method2 Polygon:A Point:3
Method2 Polygon:A Point:5
Method2 Polygon:B Point:4
Method2 Polygon:C Point:6
Method3 Polygon:A Point:3
Method3 Polygon:A Point:5
Method3 Polygon:B Point:4
Method3 Polygon:C Point:6


関連記事