ArcGIS10.1のSpatialFilterClassには少し気をつけましょうという話
ちょっとニッチな話になりますが、仕事にたまに利用する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 対応
- 作者: ESRIジャパン株式会社
- 出版社/メーカー: ESRIジャパン
- 発売日: 2013/07/24
- メディア: 単行本
- この商品を含むブログを見る