最近SQL Server 2008の記事ばっかりな件について

誤解があるようなので少しだけコメントしておくと、別にPostGISイラネというわけではありません。オープンソースGISが割とお仕事として成り立つようになってきたのでつい就業時間中にいろいろ調べ物してしまいます。なのでオープンソース系はネタをみつけても日記に書きづらいけど、仕事で使っていないプロプラなSQL Serverの話なら気兼ねなく書けるという変な状況に。

まぁそんなどうでもいい話はおいておいて、.NET編Part1として.NETのデータタイプとしてのSqlGeometry, SqlGeographyについて書いてみます。

C#でGeometry, Geographyを使ってみる

SqlGeometry, SqlGeography型は単体で使えるのでしょうか。さっそくC#のコンソールプログラム書いて試してみます。

using System.Text;
using Microsoft.SqlServer.Types;
using System.Data.SqlTypes;

namespace GeomGeogTypes1
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                // (1)Geometry作る
                SqlGeometry geomPoint = SqlGeometry.STGeomFromText(new SqlChars("POINT(35 135)"), 4326);
                SqlGeometry geomPolygon = SqlGeometry.STGeomFromText(new SqlChars("POLYGON((35 135, 35 137, 36.5 135, 35 135))"), 4326);
                // (2)少しずらしてGeography作る
                SqlGeography geogPoint = SqlGeography.STGeomFromText(new SqlChars("POINT(35 136)"), 4326);
                SqlGeography geogPolygon = SqlGeography.STGeomFromText(new SqlChars("POLYGON((35 136, 35 138, 36.5 136, 35 136))"), 4326);
                
                // (3)GEOMETRYの位置と面積
                Console.WriteLine("(3):geomPoint:{0}\ngeomPolygon={1}", new String(geomPoint.STAsText().Value), new String(geomPolygon.STAsText().Value));
                Console.WriteLine("(3):面積@Geometry:{0}\n", geomPolygon.STArea().Value);

                // (4)GEOGRAPHYの位置と面積
                Console.WriteLine("(4):geogPoint:{0}\ngeogPolygon={1}", new String(geogPoint.STAsText().Value), new String(geogPolygon.STAsText().Value));
                Console.WriteLine("(4):面積@Geography:{0}\n", geogPolygon.STArea().Value);

                // (5)異なる型での重なり判断...は無理(変換要)
                SqlGeography geogFromGeom = SqlGeography.STGeomFromText(geomPolygon.STAsText(), 4326);
                Console.WriteLine("(5):2つのポリゴン重なりあり?:{0}\n", geogPolygon.STIntersects(geogFromGeom).ToString());

                // (6)GEOMETRYで重なりフィーチャー生成
                SqlGeometry geomFromGeog = SqlGeometry.STGeomFromText(geogPolygon.STAsText(), 4326);
                Console.WriteLine("(6):重なり部分@Geometry:{0}", geomPolygon.STIntersection(geomFromGeog).ToString());
                Console.WriteLine("(6):ちがう部分@Geometry:{0}\n", geomPolygon.STDifference(geomFromGeog).ToString());

                // (7)GEOGRAPHYで重なりフィーチャー生成
                Console.WriteLine("(7):重なり部分@Geography:{0}", geogPolygon.STIntersection(geogFromGeom).ToString());
                Console.WriteLine("(7):ちがう部分@Geography:{0}\n", geogPolygon.STDifference(geogFromGeom).ToString());

            }
            catch (Exception e)
            {
                Console.WriteLine("{0}", e.Message);
                Console.WriteLine("{0}", e.StackTrace);
            }
            Console.ReadKey();
        }
    }
}

コンパイルするには、Microsoft.SqlServer.Types.dll*1を参照設定して、実行環境にはSqlSpatial.dll*2も置く必要があります。DLL2つあわせて500KB弱。
これを、SQL Server が入っていない環境にもっていって動かしてみます。結果は....

(3):geomPoint:POINT (35 135)
geomPolygon=POLYGON ((35 135, 35 137, 36.5 135, 35 135))
(3):面積@Geometry:1.5

(4):geogPoint:POINT (35 136)
geogPolygon=POLYGON ((35 136, 35 138, 36.5 136, 35 136))
(4):面積@Geography:15193890918.7112

(5):2つのポリゴン重なりあり?:True

(6):重なり部分@Geometry:POLYGON ((35 136, 35.75 136, 35 137, 35 136))
(6):ちがう部分@Geometry:POLYGON ((35 135, 36.5 135, 35.75 136, 35 136, 35 135))

(7):重なり部分@Geography:POLYGON ((35.004100371491738 136.99469190018391, 35.761
206832024406 136.00000002190484, 35.004100499758216 136.00000001975212, 35.00307
5386599093 136.49999931072208, 35.004100371491738 136.99469190018391))
(7):ちがう部分@Geography:MULTIPOLYGON (((35.003075386599093 136.49999931072208,
35.004100499758216 136.00000001975212, 35.000000005283141 136.00000001974058, 35
.003075386599093 136.49999931072208)), ((34.999999973649494 138.00000000826108,
36.5 136, 35.761206832024406 136.00000002190484, 35.004100371491738 136.99469190
018391, 34.999999973649494 138.00000000826108)))

SQL ServerSQL Serverへの接続なくても一応動くみたいです。
(6)と(7)の部分だけ、結果の雰囲気が極端に違うので補足説明しておくと、まず、(6)のGeometry型ではPOLYGONをこんな2次元の図形として扱っています。

一方、(7)のGeography型は、POLYGONを直交座標に投影したときにこーんな形に見えるように扱っています。

地球の形状を考慮して、大圏コースで線を引いてくれる、と思ってください。どっちかが正しいモデル、とかではなく用途次第なんですが、普通の人はGeographyを使っとけば安心でしょう。一方Geometryの邪道な使いみちとしては、地図関係ない人でも、複雑な画面クリッピング領域計算に疲れたときの手抜きとかに使えるかもしれません*3

...続く

*1:C:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\Binn とかにある。DLL置いてる場所も場所だし、これを参照してるアプリをクライアントにばらまくにはSQL Server Expressを同時にばらまかないといけないのかとかいろいろ問題あり。まだCTPなんでリリースまでにはなんとかなるんじゃね?

*2:同上。

*3:とはいえそういうチューニングをする必要のあるシチュエーションを考えると無理ありまくり