当前位置:首页 > PHP教程 > PHP总结归纳

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

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

  首先查资料,了解了一下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 < 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 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居然说是polygon,试了gdal1.6、gdal1.7,应该是ogr的问题,不搞了,累觉不爱啊

  总之导esri shape用geometry模式还是可以的,中文问题解决了,配和sqlserver的update语句基本能解决问题


【说明】本文章由站长整理发布,文章内容不代表本站观点,如文中有侵权行为,请与本站客服联系(QQ:)!