利用GDAL/OGR导空间数据到SQLServer2008

原创
2016-06-07 16:21:57 1022浏览

网上有个工具可以做到,可惜导入的中文是乱码,搜索了一圈好像没什么解决办法,于是想自己搞一个,哎,一搞才知道麻烦重重啊~ 首先查资料,了解了一下SQLServer中的空间数据分两种,Geometry和Geography,一种是平面一种球面,比如在做距离计算时结果是不一

  网上有个工具可以做到,可惜导入的中文是乱码,搜索了一圈好像没什么解决办法,于是想自己搞一个,哎,一搞才知道麻烦重重啊~

  首先查资料,了解了一下SQLServer中的空间数据分两种,Geometry和Geography,一种是平面一种球面,比如在做距离计算时结果是不一样的啊

  所以我必须先Geography球面坐标系,但这玩意儿有限制啊,比如多边形外环方向必须是逆时针,内环方向必须是顺时针,不能超过一个半球等等

  不管了先做,加载GDAL和ORG,打开MapInfo图层,遍历之,取字段正常,取几何个数正确,下一步将几何数据导出,方法很多,支持OpenGIS的系统

  都支持WKT和WKB,,为了方便选ExportToWkt,然后生成 INSERT语句,差不多了,执行之,问题来了:Sqlserver报错,说什么

  消息 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

  {

  ///

  /// 判断环的是否为顺时针方向

  ///

  ///

  /// True顺时针,False逆时针

  private static bool IsRingClockwise(IList pp)

  {

  double t = 0;

  for (var i = 1; 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

  }

  //判断是否是环

  public static bool IsRing(IList 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 pts, bool resverse)

  {

  var sl = new List();

  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();

  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导空间数据到SQLServer2008 三联

  这明明是一条线和一个多边形组成的啊,GDAL/OGR居然说是POLYGON,试了GDAL1.6、GDAL1.7,应该是OGR的问题,不搞了,累觉不爱啊

  总之导ESRI Shape用Geometry模式还是可以的,中文问题解决了,配和SQLServer的Update语句基本能解决问题

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn核实处理。