当前位置: 首页 > 知识库问答 >
问题:

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

须志新
2023-03-14

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

我们正在使用PostgreSQL数据库中的ST_距离函数。

当我们将计算出的距离与Google Earth进行比较时,两者之间存在着巨大的差异。

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

你知道怎么回事吗?

我在下面给出了我们用PostgreSQL测试的示例查询,以及Google Earth的屏幕截图。

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  |

以下是谷歌地球的截图:

  1. 地点1平面2
  2. 地点1目标1
  3. 地点1托波托2
  4. Place2topot1
  5. 地点2托波托2

提前谢谢!!

以下是从Google Earth导出的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中选取了视觉上最接近位置1的点,并将其标记为位置3。

当我们在地图上查看时,看起来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   |

而在地图上: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>

共有1个答案

太叔富
2023-03-14

您在PostGIS中的功能似乎与谷歌中的功能不同。。。这是我通过想象得到的。

现在还有两个问题。第一,几何学和地理学的区别。第二,距离计算。

地理位置上的st_距离返回以米为单位的值。这就是为什么考虑到要素的位置,第一次查询的输出基本上是您所期望的(因为您的点是地理位置,Postgres为您将多边形投射到地理位置)。但是,几何体上的st_distance以基础投影的单位返回值,在本例中为度。这就解释了第二个查询的输出。

关于距离计算。这里尽量简洁,但影响你计算的最大的东西是潜在的投影。根据我的理解,地理类型更适合更大的区域——你会在你分析的区域的适当投影中使用几何图形得到更准确的结果。“合适的投影”取决于你在看世界的什么地方,你的目的是什么。

另外,不要假设谷歌的数据是正确的——我做了一个快速搜索,但没有找到任何关于他们如何计算距离的信息。如果他们使用不同的方法,你会得到不同的答案。。。

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

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。它们与谷歌的搜索结果相差不到厘米。

 类似资料:
  • 好吧,为了大学,我正在做一些SQL作业,但是我不知道这里有什么问题...坚持了几个小时。 所以在这里我创建了一个函数: 然后我尝试插入一个新行: 继续获取此错误: 错误:函数ins_notitie(未知,带时区的时间戳,未知,带时区的时间戳)不存在 第1行:选择ins_notitie('100001',now(),'Test note',now()) 错误:函数ins_notitie(未知,带时区

  • 此SQL生成以下内容: 此SQL生成以下内容: 基本上,我希望得到这样的结果,按城市分组,以及相同城市出现的次数。像这样的 我不是联接、子查询方面的专家,这会有帮助吗?提前谢谢。

  • 本文向大家介绍PostgreSQL数据库中窗口函数的语法与使用,包括了PostgreSQL数据库中窗口函数的语法与使用的使用技巧和注意事项,需要的朋友参考一下 什么是窗口函数? 一个窗口函数在一系列与当前行有某种关联的表行上执行一种计算。这与一个聚集函数所完成的计算有可比之处。但是窗口函数并不会使多行被聚集成一个单独的输出行,这与通常的非窗口聚集函数不同。取而代之,行保留它们独立的标识。在这些现象

  • 我有3列(时间,值,结果)的度量表。时间和值是时间序列数据库需要的基础。结果列标记可以具有以下值之一(成功/硬失败/软失败/未知)。 我想在给定的时间窗口内跟踪成功率(成功/总成功率)(因为我将在grafana上使用它,时间窗口可能会改变,并且应该支持动态时间范围查询) 我在流入量0.9上尝试过的东西: Grafana有一个百分比堆栈选项来显示计数值。不幸的是,它不显示百分比值。它只是显示了分布的

  • 我很难找到正确的语法,我总是有错误#1064。 错误:#1064-您的SQL语法有错误;查看与您的MariaDB服务器版本对应的手册,以了解使用near'的正确语法; 这就是代码; 定界符$$ 删除函数如果存在$$ 创建函数(iq INT, sq INT, ig INT)返回INT 开始 结束$$ 分隔符; 我在网上搜索答案,我找不到。我的语法有什么问题?