将 MSSQL 中用于 Web 映射(Leaflet、Openlayer、OpenStreetMaps、GoogleAPI 等)的投影更改为 WSG48 或任何其他格式

Posted

技术标签:

【中文标题】将 MSSQL 中用于 Web 映射(Leaflet、Openlayer、OpenStreetMaps、GoogleAPI 等)的投影更改为 WSG48 或任何其他格式【英文标题】:Change projection in MSSQL for web mapping (Leaflet,Openlayer, OpenStreetMaps, GoogleAPI, ...) to WSG48 or any other format 【发布时间】:2017-06-15 00:06:08 【问题描述】:

我在 MSSQL 服务器中有一些这样的 WKT/WKB 数据,并希望借助传单、Openlayer、OpenStreetMaps 或 GoogleAPI 在地图上显示它们。我的数据如下所示:

POLYGON ((1736946.0983 5923253.9175, 1736895.6852 5923333.9451, 1736936.0082 5923356.6991, ......))

这种格式

 EPSG:2193

如下图

并希望将它们转换为

  WGS48 or EPSG:4326

我正在尝试将它们添加到传单中,似乎我需要将此数据转换为适当的格式,如下所示:

[[42.353770, -71.103606], [42.355447, -71.104475], [42.362681, -71.089830], [42.361829, -71.079230]]

不幸的是,我不知道如何进行这种转换。

我尝试了一些类似的方法

[1.]。错误:

 A .NET Framework error occurred during execution of user-defined routine or aggregate "geography": 
 System.FormatException: 24201: Latitude values must be between -90 and 90 degrees.

[2.]查询:

select  GEOGRAPHY::STPolyFromText ([stastxt],4326) from mytable
Error:
 A .NET Framework error occurred during execution of user-defined routine or aggregate "geography": 
 System.FormatException: 24201: Latitude values must be between -90 and 90 degrees.

[3.] 没有成功

[4.] 当我将 Declared SRS 设置为 EPSG:2193 时,我可以将此数据视为 GeoServer 中的一个层

在对这个问题做了更多研究之后, 问题是:

我能否仅在 MSSQL 服务器或 Leaflet 中进行此转换,或者我需要使用 Proj4net 等其他工具并将 '(' 替换为 '['?

【问题讨论】:

您必须将这些坐标重新投影到 WGS84 (EPSG:3857) 纬度和经度或define the matching CRS。这些坐标来自哪个区域? 感谢 Chrki,新西兰,我在我的问题中添加了更多信息,如何将 MSSQL 中的“(”转换为传单中的“[”? 当您说数据库中有 WKT 时,我假设它只是作为文本存储(基于您上面将其转换为地理实例的尝试)。你从哪里得到的?对我来说,它看起来像几何数据(而不是地理)。 是的,这是真的 Ben,我是从 ([Geom].[STAsText]()) 那里得到的 我已经调整了我的问题,因为找到了更多信息。谢谢 【参考方案1】:

最后,我开发了一个有趣的解决方案,我将逐步解释我的解决方案,因为我相信其他人也面临类似的问题。

第一点是要知道数据是哪个投影(src)和你想要哪个投影(dst)。通常,dst 是EPSG:4326EPSG:3857WGS48。对于这个解决方案,我需要找到其背后的正确数学,所以我使用了这个网站 https://mygeodata.cloud/cs2cs/ 找到 src 和 dst 的正确格式(如果您熟悉 R,它有一个函数,也称为 spTransform)。另一个原因是我将使用 Proj4 组件进行此转换。另一个关键步骤是转换为 GeoJson,因为这些 web 地图可以读取 GeoJson 文件。我不想将我的数据写入物理 GeoJson 文件,所以我在 MSSQL 中按需进行了转换(无需将其作为 GeoJson 文件写入某处)。

    用 C# 创建一个库,并获取一个 dll。 将此导入 MSSQL 好好享受吧

第一部分的代码:通过Nugget安装DotSpatial

 using Microsoft.SqlServer.Server;
 using System;
 using System.Collections;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;


public class classval

    public string line;
    public string src;
    public string dst;

    public classval(string line, string src, string dst)
    
        this.line = line;
        this.src = src;
        this.dst = dst;
    





public class CLRProjection

    private static IEnumerable<classval> ConvertedEnumerable(string line, string src, string dst)
    
        return new List<classval>  new classval(line, src, dst) ;
    

    [SqlFunction(FillRowMethodName = "FillRow")]
    public static IEnumerable ToLatLong(string Geometry, string src, string dst)
    
        return ConvertedEnumerable(Geometry, src, dst);
    

    private static void FillRow(Object classvalobj, out string Geometry, out string srcprj, out string dstprj)
    

       classval geomobj = (classval)classvalobj;
        string _geometry = geomobj.line; //"POLYGON ((1736946.0983 5923253.9175,....))";
    string proj4_src = geomobj.src; //"+proj=tmerc +lat_0=0 +lon_0=173 +k=0.9996 +x_0=1600000 +y_0=10000000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs ";
    string proj4_dst = geomobj.dst;//"+proj=longlat +datum=WGS84 +no_defs";
    _geometry = _geometry.Replace(",", " , ");
    _geometry = _geometry.Remove(0, _geometry.IndexOf('('));
    _geometry = _geometry.Replace("(", "[ ");
    _geometry = _geometry.Replace(")", " ]");
    string[] splitbycomma = _geometry.Split(',');

    foreach (var itembycomma in splitbycomma)
        

            string tmpitem = itembycomma;
            tmpitem = tmpitem.Replace('[', ' ');
            tmpitem = tmpitem.Replace(']', ' ');
            tmpitem = tmpitem.Trim();
            string[] splitbyspace = tmpitem.Split(' ');
            for (int ibs = 0; ibs < splitbyspace.Length - 1; ibs++)
            

                double[] x =  double.Parse(splitbyspace[ibs]) ;
                double[] y =  double.Parse(splitbyspace[ibs + 1]) ;
                double[] z = new double[x.Length];
                //rewrite xy array for input into Proj4
                double[] xy = new double[2 * x.Length];
                int ixy = 0;
                for (int i = 0; i <= x.Length - 1; i++)
                
                    xy[ixy] = x[i];
                    xy[ixy + 1] = y[i];
                    z[i] = 0;
                    ixy += 2;
                
                double[] xy_geometry = new double[xy.Length];
                Array.Copy(xy, xy_geometry, xy.Length);



                DotSpatial.Projections.ProjectionInfo src =
                    DotSpatial.Projections.ProjectionInfo.FromProj4String(proj4_src);
                DotSpatial.Projections.ProjectionInfo trg =
                    DotSpatial.Projections.ProjectionInfo.FromProj4String(proj4_dst);

                DotSpatial.Projections.Reproject.ReprojectPoints(xy, z, src, trg, 0, x.Length);


                ixy = 0;
                for (int i = 0; i <= x.Length - 1; i++)
                
                _geometry = _geometry.Replace(xy_geometry[ixy].ToString() + " ", "[" + xy[ixy + 1].ToString() + " , ");
                _geometry = _geometry.Replace(xy_geometry[ixy + 1].ToString() + " ", xy[ixy].ToString() + " ] ");
                _geometry = _geometry.Replace("- ", "-");
                    string tt = (i + 1 + " " + xy[ixy] + " " + xy[ixy + 1]);

                    ixy += 2;
                

            
        
    _geometry = _geometry.Replace("  ", " ");
    _geometry = _geometry.Replace(" [ ", "[");
    _geometry = _geometry.Replace(" ] ", "]");
    _geometry = _geometry.Replace(" , ", ",");
    srcprj = proj4_src;
    dstprj = proj4_dst;
    Geometry = _geometry;
    


第二部分的代码(MSSQL内部)

  ALTER DATABASE test SET trustworthy ON
 CREATE ASSEMBLY CLRFunctionAssem
 FROM N'C:\Users\...\bin\Debug\Convertor_Projection.dll'
 WITH PERMISSION_SET = UNSAFE
 GO


 CREATE FUNCTION dbo.ToLatLong(@Geometry nvarchar(max), @src nvarchar(max),@dst nvarchar(max))
 RETURNS TABLE
 ( _geom  nvarchar(max) ,srcprj  nvarchar(max) ,dstprj  nvarchar(max) 
) with execute as caller
AS
 EXTERNAL NAME CLRFunctionAssem.[CLRProjection].[ToLatLong]

MSSQL 代码

 SELECT       
  [parcelid]
  ,[Geom1]
  ,[stastxt]
   ,conv._geom

 FROM [test].[dbo].[TEST_JSON] as a  CROSS APPLY dbo.ToLatLong (a.
[stastxt],'+proj=tmerc +lat_0=0 +lon_0=173 +k=0.9996 +x_0=1600000 +y_0=10000000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs','+proj=longlat +datum=WGS84 +no_defs') as conv
 where [stastxt] is not null

MSSQL2016 有 JSON functiality,而旧版本没有这个能力。

输出

对我有帮助的资源是:

1,2,3

【讨论】:

【参考方案2】:

您可以使用插件Proj4Leaflet 在 Leaflet 中进行转换。

【讨论】:

与我的相比,这是一个更快的解决方案,但不会将 ( 更改为 [ 也不会更改 long 和 lat 的顺序。

以上是关于将 MSSQL 中用于 Web 映射(Leaflet、Openlayer、OpenStreetMaps、GoogleAPI 等)的投影更改为 WSG48 或任何其他格式的主要内容,如果未能解决你的问题,请参考以下文章

使用 XML 映射向表添加模式前缀 - 需要将 MSSQL 数据库转换为 MySQL

mssql 和mysql 数据自动同步程序

ORM - 特定于用于 .NET 的 SQL Server 2008+

用于导出Web映射任务的Esri Web映射的示例JSON表示

MSSQL:C# 函数可以实现视图吗?

用于使用 Azure SQL Server 数据的 C# Web API