【问题标题】:Google Maps and SQL Server LINESTRING length inconsistentGoogle Maps 和 SQL Server LINESTRING 长度不一致
【发布时间】:2015-08-12 16:44:56
【问题描述】:

Google 地图和 MSSQL 在如何使用 SRID 4326 计算折线/线串的距离/长度方面似乎存在分歧。

MSSQL:

SELECT geography::STGeomFromText('LINESTRING(-98.78 39.63,2.98 27.52)', 4326).STLength()

结果:9030715.95721209

然后是谷歌地图:

http://jsbin.com/niratiyojo/1/

结果:9022896.239500616

起初我以为这只是地球测量的不同半径,所以我尝试了一下,结果发现它更多。

我需要我的 JavaScript 界面与 MSSQL 报告的内容相匹配,以保持一致和准确。我在哪里或如何找到 MSSQL 如何计算它们的 STLength() 以及它可以在 JavaScript 中复制吗?

更新:

我意识到如果我这样做了

SELECT GEOGRAPHY::STGeomFromText('LINESTRING(-98.78 39.63,2.98 27.52)', 104001).STLength() * 6378137

然后MSSQL返回9022896.23950062

MSSQL 中的新 SRID:

新的“单位球体”空间参考 ID 默认空间参考 SQL Server 2012 中的 ID (SRID) 是 4326,它使用公制作为 它的计量单位。这个 SRID 也代表了真实的 地球的椭球体形状。虽然这种表示是 最准确,计算精确椭球也更复杂 数学。 SQL Server 2012 在速度和 准确度,通过添加新的空间参考 ID (SRID) 104001, 使用半径为 1 的球体来表示一个完美的圆形地球。

所以问题是谷歌地图在计算中没有使用真正的椭球体。我正在寻找一个 javascript 函数,它得到 9030715.95721209 的见证。

我在这里尝试了 Vincenty 直接公式:http://jsbin.com/noveqoqepa/1/edit?html,js,console,虽然它更接近我仍然无法匹配 MSSQL

编辑 2:

我能够找到它使用的测量值:

SridList._sridList.Add(4326, new SridInfo(4326, "EPSG", 4326, "GEOGCS[\"WGS 84\", DATUM[\"World Geodetic System 1984\", ELLIPSOID[\"WGS 84\", 6378137, 298.257223563]], PRIMEM[\"Greenwich\", 0], UNIT[\"Degree\", 0.0174532925199433]]", "metre", 1.0, 6378137.0,
6356752.314));

但似乎将这些插入 Vincenty 并没有运气。

【问题讨论】:

  • 我唯一能发现的是,半短轴倾向于多表示两位小数,这对整体结果的影响为零。我真的不知道 MSSQL 是如何确定它的距离的。
  • 使用Live examples on the Vincenty solutions of geodesics on the ellipsoid page 下的表格我得到 9,030,706.728 m,这非常接近 9030715.95721209(9x10^9 米中的 9 米)
  • 是的,这也是我使用帖子底部发布的 jsbin 解决方案获得的相同距离。它非常接近,但我需要更准确。
  • 我不认为 Maps API 中提供的功能适用于需要您正在寻找的极端精度的重型 GIS 应用程序。对于这些类型的应用程序,您最好找到一些其他满足您特定需求的库并使用它。你可以试试github.com/chrisveness/geodesy,虽然我不确定它是否会给你比其他人提到的库更准确的计算。

标签: javascript sql-server google-maps gis sqlgeography


【解决方案1】:

在经历了所有不同的选项之后,您最好的选择似乎是在服务器和客户端上使用相同的文字函数。这可以通过两种方式实现:

方法一:在客户端使用SQL函数

在这种情况下,您将在客户端上触发对服务器的 AJAX 查询,然后服务器会查询数据库以获取您想要的特定计算并将其返回给客户端。

方法二:在SQL中使用Javascript函数

这听起来很不可能,但是使用xp_cmdshell 可以使用execute command line commands from sql,并且您可以使用node.js 之类的东西从终端运行javascript,所以剩下的就是实现Vincenty 函数called from the command line

这里最大的问题是性能如何。每隔几秒启动和停止一个node 实例似乎是一个相对糟糕的主意,因此在节点中编写一个服务来完成这项工作会更加优化,但是我不知道@987654325 的最佳方法是什么@ 与这样的服务进行交互。最简单的方法可能是让它向 localhost:8888/?lat1=&lng1=&etc. 之类的东西发出 http 请求,但这开始几乎和方法 1 一样复杂。

结论

方法 1 似乎仍然是最合理的方法,尽管方法 2 为您提供了更大的灵活性,可以完全按照您的意愿行事。对于私人项目或完美主义项目,我认为我会采用方法 2,对于“我们需要完成这个,我们没有时间进行惊喜或优化”——有点项目,我认为我会建议方法 1。

【讨论】:

  • 如果准确性不是问题,那么内置函数和 MS SQL SRID 104001 的谷歌地图将作为匹配足够接近的解决方案。在我的特定应用程序中,准确性确实很重要,但似乎方法 2 可能是需要的。
【解决方案2】:

您确实意识到 Google 地图使用 Web Mercator,即 EPSG:3857,而不是 WGS EPSG:4326? Web Mercator article 及其引用可能有助于解释差异。

尝试 GeographicLib 和/或 Proj4js 的 JavaScript 实现。正如this question/answer on gis.stackexchange 所指出的,空间数据转换的底层实现可能略有不同。你至少需要比 Vincenty direct 更好的东西。

【讨论】:

  • GeographicLib 返回 9030706.727997527,这与 Vincenty 公式相同。我开始认为 MSSQL 不准确......
  • 可以在服务器上使用Vincenty公式代替MSSQL公式吗?另一个建议是当折线发生变化时在客户端使用 javascript 版本,并在计时器上或绘制完成后将线的端点与后端同步。
  • 鉴于我认为对 Google 地图使用的投影可能存在误解,您可能需要查看Geodesic lines, circles, envelopes in Google Maps 和相关说明,这些说明可能有助于解释可能导致您的差异的差异。
  • 我知道谷歌地图使用的投影,我一直在使用的 javascript 方法依赖于 4326。谷歌地图折线的测地线选项实际上对其长度的内部计算没有任何影响一条折线(很奇怪)。他们只取直线中的每一个长/纬点,并根据地球的球形模型进行计算。这就是为什么 google 和 MSSQL 相距甚远,因为 Vincenty 使用地球的椭球模型,并且更接近 MSSQL,但我找不到微软使用的该死公式,我只知道它可能是椭球
  • 我的解决方案似乎是通过使用地球的球形模型来简化 MSSQL 长度函数,以便它匹配谷歌地图并将其存储为带有几何的列。另一种方法是编写一个使用 vincenty 的 SQL 过程。我必须以一种或另一种方式使它们匹配,我更喜欢最准确的方式,但似乎这将是最昂贵的。
【解决方案3】:

您可以确定的唯一方法是让 Microsoft 程序员通过电话、反汇编代码,或者只是向 SQL Server 数据库发送查询并接受它的结果。

这可能对您有所帮助: Using SQL Spatial Types in a .NET Application

如果你想尝试反汇编,我相信方法在Microsoft.SqlServer.Types.dll文件中。

【讨论】:

  • 选项 2 似乎比选项 1 更容易。选项 3 不适用于解决方案。关于如何拆卸它有什么建议吗?我假设它是用 .NET 语言编写的,这种语言在防止反汇编方面是出了名的糟糕。
  • 如果您尝试匹配 SQL Server 所做的事情,那么我假设您在后端使用 SQL Server 做其他事情。如果不是...你为什么要关心它是否与 SQL Server 匹配?如果您已经连接到 SQL Server,为什么将几何查询放在 SQL Server 或查询 SQL Server 的 Web 服务上的过程中不可行?
  • 我正在使用 javascript 界面创建一个 LRS 系统,我需要知道折线的距离大约每秒 10 次,因为它会发生变化,这可以使用纯 javascript 轻松完成(我已经完成它)。这不能通过对 SQL Server 的后端调用来完成,因为开销太大并且会向服务器发送垃圾邮件。但是,javascript函数计算的距离必须与SQL server相匹配,否则视图和模型之间会出现差异。
  • 我能够反编译Microsoft.SqlServer.Types.dll 没问题,但我看到它在SqlServerSpatial120.dll 中引用了一个函数GLNativeMethods.GeodeticPointDistance。加载空间 dll 并没有产生高级代码,因为它似乎不是 .NET。我将它加载到 IDA 中并且能够获得程序集,但它很难掌握。我确实设法找到了一个字符串,它引用了它使用的测量值。我将其作为编辑发布在原始问题中
  • 能够从代码中获取 C,但它确实被混淆了。我希望我能找到一个独特的数字来帮助我找到公式。有趣的是,唯一的数字 16384 没有出现在函数中,这表明它可能不是 Vincenty 。以下是有用的功能:pastebin.com/t1g5UCFS
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-05-01
  • 2015-08-27
  • 1970-01-01
  • 2014-02-07
  • 2014-01-24
  • 1970-01-01
  • 2021-12-14
相关资源
最近更新 更多