三十路SEの小遣い稼ぎ

ブログ初心者の小遣い稼ぎを目論むサイトです。目標の月2000円は達成できたので、自分が気になったニュースも合わせて紹介します。

ArcGIS10.1のSpatialFilterClassには少し気をつけましょうという話

【PR】

ちょっとニッチな話になりますが、仕事にたまに利用するArcGISについて書いてみようと思います。

事の発端

ArcGISのArcObjectsを利用した検索と言えば、
みんな大好きIFeatureClass.Search()メソッドですよね!
(知ってる人だけ付いてきて!)

更にその検索で空間検索したい場合は、SpatialFilterClassを利用します。
SpatialFilterClassの利用方法はこんな感じ

ISpatialFilter filter = new SpatialFilterClass()
{
    Geometry = point, // 重なり対象
    GeometryField = featureClass.ShapeFieldName, // 空間情報保持列名
    SearchOrder = esriSearchOrder.esriSearchOrderSpatial, // 検索優位条件
    SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects // 空間検索方式
};

上記クラスを利用した検索バッチプログラムを作成/テストを完了。
成果物を客先に納品したときに事件が起きました。

「あの~、ログ確認したらエラーメッセージが出てて終了してるんですけど。」

ホワッツ!

エラーの原因

社内テストだと上手く行ってたのに、客先で失敗するのはなぜ?
ライセンス認証が通ってない?
対象テーブルが存在しない?必要な列名が存在しない、または名前が違う?

どれも違いました。
エラーの原因はメモリ枯渇によるアウトオブメモリーでした。
下記メソッドを実行する度に100MB程メモリが増加し、検索処理が終わった後も20MB程しかメモリが解放されていませんでした。

featureClass.Search(filter, true);

※社内テストだとテスト件数少なすぎて気づいてなかった。。。

対策

ComObjectsの解放漏れが無いか、作りが悪いのではないか等色々調べましたが、
SpatialFilterClassのあるプロパティを変更するとメモリが増加しないことが判明!
そのプロパティは「SpatialRel」

メモリ増加前はSpetialRelプロパティにesriSpatialRelEnum.esriSpatialRelIntersectsを
設定していたのですが、代わりにesriSpatialRelEnum.esriSpatialRelEnvelopeIntersects
設定する事でアウトオブメモリーを回避する事が出来ました。

ただしesriSpatialRelEnum.esriSpatialRelEnvelopeIntersectsを指定すると、
対象図形を完全に含む矩形をもとに空間検索が実行される為、
不必要なデータまで取得されてしまいます。

必要なデータだけ抽出する為に追加したロジックがこちら

IFeature feature = featureCursor.NextFeature();
 while (feature != null)
{
    IRelationalOperator relOpe = (IRelationalOperator)feature.Shape;
    if (!relOpe.Contains(point))
    {
        feature = featureCursor.NextFeature();
        continue;
    }
    feature = featureCursor.NextFeature();
}

IRelationalOperatorのContainsメソッドで再絞り込みを掛けてます。

最後に

落ちた理由がメモリ枯渇によるものだとはすぐわかりましたが、
何故そうなるかを突き止めるのに苦労しました。。。
SpatialFilterClassのプロパティを変えただけで改善されたので
ArcGISの不具合かなぁと考えています。

皆様もお気をつけて!

※ArcGIS10.1では発生しますが、ArcGIS10.2では発生しません。
 これもバグかなと思う要因の一つですw

ArcGIS for Desktop 逆引きガイド 10.1 & 10.2 対応

ArcGIS for Desktop 逆引きガイド 10.1 & 10.2 対応