首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> SQL Server 資料庫 >> 關於SqlServer

使用 GDAL/OGR 將空間數據導入 SQL Server 2008:WKT 修正與坐標系實戰

     編輯:關於SqlServer

項目背景與核心挑戰

將 MapInfo (.tab) 空間數據遷移至 SQL Server 2008 空間類型時,遭遇兩大核心問題:

  1. 中文亂碼:現有工具導入後屬性字段亂碼。
  2. Geography 類型半球限制:SQL Server geography 要求多邊形外環逆時針、內環順時針,且單一實例不超過半球,違規即拋出 24205 錯誤。

技術棧與數據流程

  • GDAL/OGR 1.7+(C# 封裝)讀取 MapInfo 圖層
  • 幾何導出為 WKT(Well-Known Text)
  • 生成 geography::STGeomFromText(wkt, 4326) 插入腳本
  • 遭遇半球/環方向錯誤 → 需預處理 WKT 修正環順序

關鍵代碼:WKT 環方向自動修正算法

核心邏輯:計算環有向面積(鞋帶公式),判斷順逆時針;按 Geography 規則調整:

  • 外環(第一個環)必須逆時針(面積 > 0)
  • 內環(孔)必須順時針(面積 < 0)
public static class WktFixer
{
    // 鞋帶公式計算有向面積,返回 true 表示順時針
    private static bool IsRingClockwise(IList ring)
    {
        double area = 0;
        for (int i = 1; i < ring.Count; i++)
            area += ring[i-1].X * ring[i].Y - ring[i].X * ring[i-1].Y;
        area += ring[ring.Count-1].X * ring[0].Y - ring[0].X * ring[ring.Count-1].Y;
        return area < 0; // 負值為順時針
    }

    public static string FixPolygonOrientation(string wkt)
    {
        if (!Regex.IsMatch(wkt, @"POLYGON", RegexOptions.IgnoreCase))
            return wkt; // 僅處理 POLYGON

        var matches = Regex.Matches(wkt, @"\(([^()]+)\)");
        string result = wkt;

        for (int i = matches.Count - 1; i >= 0; i--)
        {
            var m = matches[i];
            string coords = m.Value.Trim('(', ')');
            var pts = coords.Split(',')
                .Select(s => s.Trim().Split(' '))
                .Where(p => p.Length == 2)
                .Select(p => new Point(double.Parse(p[0]), double.Parse(p[1])))
                .ToList();

            if (pts.Count < 4 || pts.First().X != pts.Last().X || pts.First().Y != pts.Last().Y)
                continue; // 非閉合環

            bool isClockwise = IsRingClockwise(pts);
            // 外環(i=0)應逆時針,內環應順時針
            bool needReverse = (i == 0) ? isClockwise : !isClockwise;

            if (needReverse)
            {
                pts.Reverse();
                string fixedRing = "(" + string.Join(",", pts.Select(p => $"{p.X:F8} {p.Y:F8}")) + ")";
                result = result.Remove(m.Index, m.Length).Insert(m.Index, fixedRing);
            }
        }
        return result;
    }
}

實戰踩坑記錄

  1. GeometryCollection 識別錯誤:OGR 將「線+面」混合要素誤報為 POLYGON,實際 WKT 為 GEOMETRYCOLLECTION。對策:解析 WKT 類型標籤,分類處理。
  2. 多邊形內環反轉邏輯缺陷:代碼中 TODO 註釋指出內環不應整體反轉。修正:分別判斷每個環方向,僅在違規時單環反轉。
  3. 跨半球大幾何:中國全圖超過半球,必須改用 geometry 平面類型,或拆分為多個 geography 實例。
  4. .NET 2.0 兼容性:避免使用 List.ToArray()、Lambda 等 3.5+ 特性,改用 ArrayList、匿名委託。

最終可行方案

  • 屬性數據:GDAL 讀取 → 參數化 SQL 插入 → 解決編碼問題(連接字符串指定 CharacterSet=UTF-8)。
  • 空間數據:導出 WKT → WktFixer.FixPolygonOrientation → geometry::STGeomFromText(平面類型,無半球限制)。
  • 後處理:SQL 端通用 UPDATE 修正殘留拓撲錯誤(MakeValid())。

經驗總結:空間數據遷移 80% 工作量在數據清洗與拓撲修正。GDAL/OGR 是強大的讀取引擎,但 WKT 輸出需二次驗證;SQL Server 空間類型選型(Geometry vs Geography)應由業務範圍決定,全球/大範圍數據首選 Geometry。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved