gpt4 book ai didi

postgresql - PostgreSQL 数据库中的 ST_Distance 函数计算错误的距离?

转载 作者:行者123 更新时间:2023-11-29 12:25:31 27 4
gpt4 key购买 nike

我们正在开发一个应用程序,该应用程序涉及根据存储在 PostgreSQL 表中的多边形计算给定点的最短距离。

我们正在使用 PostgreSQL 数据库中的 ST_Distance 函数。

当我们将计算出的距离与 Google 地球进行比较时,它们之间存在巨大差异。

当然,Google 和 PostgreSQL 都不可能是错的(或者他们是错的?),所以我们显然在这里遗漏了一些东西。

知道哪里出了问题吗?

我在下面给出了我们使用 PostgreSQL 测试过的示例查询以及来自 Google 地球的屏幕截图。

SELECT ST_Distance(Place1, Place2) As Place1ToPlace2
, ST_Distance(Place1, Spot1) As Place1ToSpot1
, ST_Distance(Place1, Spot2) As Place1ToSpot2
, ST_Distance(Place2, Spot1) As Place2ToSpot1
, ST_Distance(Place2, Spot2) As Place2ToSpot2
FROM (SELECT
ST_PolygonFromText('SRID=4326;POLYGON((-74.0050636293915 40.75265123968514,-74.00500355126653 40.75268991743845,-74.00498169169283 40.75267084386348,-74.00503571044075 40.75263867886528,-74.0050636293915 40.75265123968514))') as Spot1
,ST_PolygonFromText('SRID=4326;POLYGON((-74.00503571044075 40.75263867886528,-74.00498225451273 40.75267084385684,-74.00495878551709 40.75265859837483,-74.00501023946696 40.75262521978885,-74.00503571044075 40.75263867886528))') as Spot2
,ST_GeogFromText('SRID=4326;POINT(-74.00489 40.752894)') As Place1
,ST_GeogFromText('SRID=4326;POINT(-74.004774 40.752846)') As Place2
) As foo ;

它产生以下值:

place1toplace2 |place1tospot1 |place1tospot2 |place2tospot1 |place2tospot2 |
---------------|--------------|--------------|--------------|--------------|
11.152362504 |24.608417285 |25.977083731 |26.004190091 |26.011579435 |

以下是 Google Earth 的屏幕截图:

  1. Place1ToPlace2
  2. Place1ToSpot1
  3. Place1ToSpot2
  4. Place2ToSpot1
  5. Place2ToSpot2

提前致谢!

以下是从 Google 地球导出的 KML:

<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2" xmlns:kml="http://www.opengis.net/kml/2.2" xmlns:atom="http://www.w3.org/2005/Atom">
<Document>
<name>Spot 1.kml</name>
<Style id="inline">
<LineStyle>
<color>ff0000ff</color>
<width>2</width>
</LineStyle>
<PolyStyle>
<fill>0</fill>
</PolyStyle>
</Style>
<Style id="inline0">
<LineStyle>
<color>ff0000ff</color>
<width>2</width>
</LineStyle>
<PolyStyle>
<fill>0</fill>
</PolyStyle>
</Style>
<StyleMap id="inline1">
<Pair>
<key>normal</key>
<styleUrl>#inline</styleUrl>
</Pair>
<Pair>
<key>highlight</key>
<styleUrl>#inline0</styleUrl>
</Pair>
</StyleMap>
<Placemark>
<name>Spot 1</name>
<styleUrl>#inline1</styleUrl>
<Polygon>
<tessellate>1</tessellate>
<outerBoundaryIs>
<LinearRing>
<coordinates>
-74.0050636293915,40.75265123968514,0 -74.00500355126653,40.75268991743845,0 -74.00498169169283,40.75267084386348,0 -74.00503571044075,40.75263867886528,0 -74.0050636293915,40.75265123968514,0
</coordinates>
</LinearRing>
</outerBoundaryIs>
</Polygon>
</Placemark>
</Document>
</kml>


<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2" xmlns:kml="http://www.opengis.net/kml/2.2" xmlns:atom="http://www.w3.org/2005/Atom">
<Document>
<name>Spot 2.kml</name>
<Style id="inline">
<LineStyle>
<color>ff0000ff</color>
<width>2</width>
</LineStyle>
<PolyStyle>
<fill>0</fill>
</PolyStyle>
</Style>
<StyleMap id="inline0">
<Pair>
<key>normal</key>
<styleUrl>#inline1</styleUrl>
</Pair>
<Pair>
<key>highlight</key>
<styleUrl>#inline</styleUrl>
</Pair>
</StyleMap>
<Style id="inline1">
<LineStyle>
<color>ff0000ff</color>
<width>2</width>
</LineStyle>
<PolyStyle>
<fill>0</fill>
</PolyStyle>
</Style>
<Placemark>
<name>Spot 2</name>
<styleUrl>#inline0</styleUrl>
<Polygon>
<tessellate>1</tessellate>
<outerBoundaryIs>
<LinearRing>
<coordinates>
-74.00503571044075,40.75263867886528,0 -74.00498225451273,40.75267084385684,0 -74.00495878551709,40.75265859837483,0 -74.00501023946696,40.75262521978885,0 -74.00503571044075,40.75263867886528,0
</coordinates>
</LinearRing>
</outerBoundaryIs>
</Polygon>
</Placemark>
</Document>
</kml>

!编辑 2!

我又尝试了一件事情。我从 Spot1 中提取了视觉上看起来最接近 Place1 的点并将其标记为 Place3。

当我们在 map 上看时,Place3 看起来比 Place2 更接近 Place1,但是当查询时,到 Place3 的距离给出了更高的值。

我已经检查了以下查询:

SELECT ST_Distance(Place1, Place2) As Place1ToPlace2
,ST_Distance(Place1, Place3) As Place1ToPlace3
FROM (SELECT
ST_GeogFromText('SRID=4326;POINT(-74.00489 40.752894)') As Place1
,ST_GeogFromText('SRID=4326;POINT(-74.004774 40.752846)') As Place2
,ST_GeogFromText('SRID=4326;POINT(-74.00500355126653 40.75268991743845)') As Place3
) As foo;

结果如下:

place1toplace2 |place1toplace3 |
---------------|---------------|
11.152362504 |24.608417285 |

在 map 上时: Place1ToPlace3

以下是 Place1、Place2 和 Place3 的 KML(我已经从 KML 中删除了与样式相关的标签)

<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2" xmlns:kml="http://www.opengis.net/kml/2.2" xmlns:atom="http://www.w3.org/2005/Atom">
<Document>
<name>Distance Comparison.kml</name>
<Folder>
<name>Distance Comparison</name>
<open>1</open>
<Style>
<ListStyle>
<listItemType>check</listItemType>
<bgColor>00ffffff</bgColor>
<maxSnippetLines>2</maxSnippetLines>
</ListStyle>
</Style>
<Placemark>
<name>Place 1 - 40°45&apos;9.78&quot;N 74° 0&apos;18.07&quot;W (40.752894, -74.00489)</name>
<open>1</open>
<LookAt>
<longitude>-74.00500758183839</longitude>
<latitude>40.75269419172616</latitude>
<altitude>0</altitude>
<heading>-0.0008536233435993688</heading>
<tilt>29.8433509629012</tilt>
<range>47.16429940085073</range>
<gx:altitudeMode>relativeToSeaFloor</gx:altitudeMode>
</LookAt>
<styleUrl>#msn_1</styleUrl>
<Point>
<gx:drawOrder>1</gx:drawOrder>
<coordinates>-74.00501944444444,40.75271666666666,0</coordinates>
</Point>
</Placemark>
<Placemark>
<name>Place 2 - 40°45&apos;9.54&quot;N 74° 0&apos;17.70&quot;W (40.752846, -74.004774)</name>
<open>1</open>
<LookAt>
<longitude>-74.00500758183839</longitude>
<latitude>40.75269419172616</latitude>
<altitude>0</altitude>
<heading>-0.0008536233435993688</heading>
<tilt>29.8433509629012</tilt>
<range>47.16429940085073</range>
<gx:altitudeMode>relativeToSeaFloor</gx:altitudeMode>
</LookAt>
<styleUrl>#msn_2</styleUrl>
<Point>
<gx:drawOrder>1</gx:drawOrder>
<coordinates>-74.00491666666667,40.75265,0</coordinates>
</Point>
</Placemark>
<Placemark>
<name>Place 3 - 40°45&apos;9.68&quot;N 74° 0&apos;18.01&quot;W (40.75268991743845 -74.00500355126653)</name>
<open>1</open>
<styleUrl>#msn_3</styleUrl>
<Point>
<coordinates>-74.00500277777778,40.75268888888889,0</coordinates>
</Point>
</Placemark>
</Folder>
</Document>
</kml>

最佳答案

您在 PostGIS 中的功能似乎与它们在 Google 中的位置不同...这是我通过可视化得到的结果。

Points and polygons

现在还有两个问题。一、geometry and geography的区别.二、距离计算。

geographies 上的 st_distance 返回以米为单位的值。这就是为什么你的第一个查询的输出基本上是你所期望的,给定特征的位置(因为你的点是地理,Postgres 为你将多边形转换为地理)。但是,geometries 上的 st_distance 返回以基础投影为单位的值,在本例中为度数。这解释了您的第二个查询的输出。

转到 distance calculation .在这里尽量简洁,但影响您计算的最大因素是基础投影。根据我的理解,地理类型更适合较大的区域——在适合您正在分析的区域的投影中使用几何图形,您会得到更准确的结果。 “suitable projection”取决于您正在查看世界的哪些部分以及您的目的是什么。

此外,不要假设 Google 的数据是正确的 - 我进行了快速搜索,但没有找到任何关于他们如何计算距离的信息。如果他们使用不同的方法,您会得到不同的答案...

编辑这是带有显示在屏幕截图中的坐标的查询。注意坐标值的差异!另外请注意,您屏幕截图中显示的度分秒与括号中的十进制度值不匹配!

SELECT ST_Distance(Place1, Place2) As Place1ToPlace2
, ST_Distance(Place1, Spot1) As Place1ToSpot1
, ST_Distance(Place1, Spot2) As Place1ToSpot2
, ST_Distance(Place2, Spot1) As Place2ToSpot1
, ST_Distance(Place2, Spot2) As Place2ToSpot2
FROM (SELECT
ST_PolygonFromText('SRID=4326;POLYGON((-74.0050636293915 40.75265123968514,-74.00500355126653 40.75268991743845,-74.00498169169283 40.75267084386348,-74.00503571044075 40.75263867886528,-74.0050636293915 40.75265123968514))') as Spot1
,ST_PolygonFromText('SRID=4326;POLYGON((-74.00503571044075 40.75263867886528,-74.00498225451273 40.75267084385684,-74.00495878551709 40.75265859837483,-74.00501023946696 40.75262521978885,-74.00503571044075 40.75263867886528))') as Spot2
,ST_GeogFromText('SRID=4326;POINT( -74.005019 40.752717)') As Place1
,ST_GeogFromText('SRID=4326;POINT(-74.004917 40.752650)') As Place2
) As foo ;

返回的值为 11.38223433、3.27827391、5.99175215、5.93327383、3.65564537。它们与 Google 的结果相差不到 cm。

关于postgresql - PostgreSQL 数据库中的 ST_Distance 函数计算错误的距离?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40504193/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com