利用GDAL/OGR导空间数据到SQLServer2008
网上有个工具可以做到,可惜导入的中文是乱码,搜索了一圈好像没什么解决办法,于是想自己搞一个,哎,一搞才知道麻烦重重啊~ 消息 6522,级别 16,状态 1,第 1 行 在执行用户定义例程或聚合 "geography" 期间出现 .NET Framework 错误: Microsoft.SqlServer.Types.GLArgumentException: 24205: 因为指定的输入超过了一个半球,所以它不代表有效的地理实例。每个地理实例必须能容纳在一个半球内。此错误的常见原因是某个多边形的环方向错误。 Microsoft.SqlServer.Types.GLArgumentException: 在 Microsoft.SqlServer.Types.GLNativeMethods.ThrowExceptionForHr(GL_HResult errorCode) 在 Microsoft.SqlServer.Types.GLNativeMethods.GeodeticIsValid(GeoData g) 在 Microsoft.SqlServer.Types.SqlGeography.IsValidExpensive() 在 Microsoft.SqlServer.Types.SqlGeography.ConstructGeographyFromUserInput(GeoData g,Int32 srid) 在 Microsoft.SqlServer.Types.SqlGeography.GeographyFromText(OpenGisType type,SqlChars taggedText,Int32 srid) 在 Microsoft.SqlServer.Types.SqlGeography.STGeomFromText(SqlChars geometryTaggedText,Int32 srid) 。 将geography::STGeomFromText换成geometry::STGeomFromText,没问题可以正常生成几何,哎,说明真的环方向有问题,改吧,于是有了以后代码 using System; using System.Collections.Generic; using System.Text.RegularExpressions; namespace SqlSpatialTools { public class Point { public double X { get; set; } public double Y { get; set; } public Point(double x,double y) { X = x; Y = y; } public static Point Parse(string pt) { var p = pt.Split(new[] { " " },StringSplitOptions.RemoveEmptyEntries); return p.Length == 2 ? new Point(Convert.ToDouble(p[0]),Convert.ToDouble(p[1])) : null; } public override string ToString() { return string.Format("{0:F8} {1:F8}",X,Y); } } public static class Wkt { /// <summary> /// 判断环的是否为顺时针方向 /// </summary> /// <param name="pp"></param> /// <returns>True顺时针,False逆时针</returns> private static bool IsRingClockwise(IList<Point> pp) { double t = 0; for (var i = 1; i < pp.Count; i++) t += pp[i - 1].X * pp[i].Y - pp[i].X * pp[i - 1].Y; t += pp[pp.Count - 1].X * pp[0].Y - pp[0].X * pp[pp.Count - 1].Y; return t < 0; } //判断是否是环 public static bool IsRing(IList<Point> pp) { var t = pp.Count - 1; return (t > 2 && pp[0].X == pp[t].X && pp[0].Y == pp[t].Y); } public static string[] Resverse(List<Point> pts,bool resverse) { var sl = new List<string>(); foreach (var pt in pts) { sl.Add(pt.ToString()); } if (resverse) sl.Reverse(); return sl.ToArray(); } public static string ReverseWKT(string wkt) { if (!Regex.IsMatch(wkt,"POLYGON")) return wkt; var retwkt = wkt; var ms = Regex.Matches(retwkt,@"(d+.*?d+)"); //按geography规则,多边形外环应该逆时针,内环顺时针 //POLYGON(())中第一个()中的是外形,其它的是内环 //LINESTRING()直接判断是否为逆时针即可(判断一下需要需要逆时针) if (ms.Count > 0) { for (var i = ms.Count - 1; i >= 0; i--) { var m = ms[i]; var s = m.ToString().TrimStart(new[] { '(' }).TrimEnd(new[] { ')' }); var pa = s.Split(new[] { "," },StringSplitOptions.RemoveEmptyEntries); var ls = new List<Point>(); foreach (var p in pa) { var pt = Point.Parse(p); if (pt != null) ls.Add(pt); } //TODO 多边形有内环的不能逆转,要顺时针 if (IsRing(ls)) { var rs = string.Join(",",Resverse(ls,IsRingClockwise(ls)));//如果是顺时针则逆转 retwkt = retwkt.Remove(m.Index,m.Length).Insert(m.Index,string.Format("({0})",rs)); } } return retwkt; } return wkt; } } } 以上用的.net 2.0所以string[].ToArray这种都不支持,虽然MutiPolygon和GeomertyCollection还是搞不定, 不过一般Polygon是没问题的,再次测试了一个MapInfo Table (中国面省界)基本OK,再导面县界,结果一些搞不定,导出WKT用SELECT在SQLER里试了一下,真不行啊,查了一下用网上工具导的记录,WKT是GEOMETRYCOLLECTION,而我用GDAL/OGR查出来说是POLYGON类型 这明明是一条线和一个多边形组成的啊,GDAL/OGR居然说是POLYGON,试了GDAL1.6、GDAL1.7,应该是OGR的问题,不搞了,累觉不爱啊 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |