将 MSSQL 中用于 Web 映射(Leaflet、Openlayer、OpenStreetMaps、GoogleAPI 等)的投影更改为 WSG48 或任何其他格式
Change projection in MSSQL for web mapping (Leaflet,Openlayer, OpenStreetMaps, GoogleAPI, ...) to WSG48 or any other format
我在 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)并将“(”替换为“[”?
最后,我开发了一个有趣的解决方案,我将逐步解释我的解决方案,因为我相信其他人也面临类似的问题。
第一点是要知道数据是哪个投影(src)和你想要哪个投影(dst)。通常,dst 为 EPSG:4326
、EPSG:3857
或 WGS48
。对于这个解决方案,我需要找到背后的正确数学,所以我使用了这个网站
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;
}
}
第二部分的代码(Inside 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有JSONfunctiality,旧版本没有这个能力
输出
对我有帮助的资源是:
您可以使用插件 Proj4Leaflet 在 Leaflet 中进行转换。
我在 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
在对这个问题做了更多研究之后, 问题是:
我能否仅在 MSSQL 服务器或 Leaflet 中进行此转换,或者我需要使用一些其他工具(如 Proj4net)并将“(”替换为“[”?
最后,我开发了一个有趣的解决方案,我将逐步解释我的解决方案,因为我相信其他人也面临类似的问题。
第一点是要知道数据是哪个投影(src)和你想要哪个投影(dst)。通常,dst 为 EPSG:4326
、EPSG:3857
或 WGS48
。对于这个解决方案,我需要找到背后的正确数学,所以我使用了这个网站
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;
}
}
第二部分的代码(Inside 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有JSONfunctiality,旧版本没有这个能力
输出
对我有帮助的资源是:
您可以使用插件 Proj4Leaflet 在 Leaflet 中进行转换。