如何准确存储地理位置数据,在半径范围内过滤并计算距离?

时间:2019-01-14 14:35:59

标签: postgresql postgis

我通过以下方式写新位置:

ST_SetSrid(ST_MakePoint(:longitude, :latitude), 4326)

它们保存在"profile".location下:

SRID=4326;POINT(-75.1234 35.1234)

我尝试过滤以米为单位的:radius内的配置文件,其中:ownLocation是一些由一串数字组成的位置字符串:

ST_DWithin("profile".location, :ownLocation::geometry, :radius)

然后,当我得到结果并使用以下方法计算其距离时: ST_Distance( ST_Transform("profile".location::geometry, 3857::int), ST_Transform(:ownLocation::geometry, 3857::int) ) as distance

,然后将距离从米转换为英里,我的结果有些偏离。假设我将最大半径设置为10英里以内-我回来的距离似乎为0-23英里(预计为0-10英里)。

我想知道这里哪里出了问题,并且感觉可能与投影有关,或者我使用的功能不正确。


解决方案后更新:存储为4326,显示距离为3857

存储为4326

ST_SetSrid(ST_MakePoint(:longitude, :latitude), 4326)

使用geography类型的过滤器,因此它可以接受过滤器半径作为用户将通过的米:

ST_DWithin("profile".location::geography, :ownLocation::geography, :radiusInMeters)

显示从43263857米的距离并进行校正(https://postgis.net/docs/ST_Distance.html):

ST_Distance(
ST_Transform("profile".location::geometry, 3857),
ST_Transform(:ownLocation::geometry, 3857)
) * cosd(42.3521) as distance

2 个答案:

答案 0 :(得分:3)

3857不适合计算距离,因为当您远离赤道时会引入重要的失真。

相反,您可以使用ST_Distance数据类型来使用geography

ST_Distance("profile".location::geography,:ownLocation::geography) as distance

关于st_dwithin,它使用的投影单位是度,而不是米。您还可以在此处使用geography数据类型。

答案 1 :(得分:1)

EPSG 4326的单位是度,而EPSG 3857的单位是米。

ST_DWithin(“ profile” .location,:ownLocation :: geometry,:radius)将度数作为半径而不是米或英里。

将“配置文件” .location和:ownLocation :: geometry转换为3857应该有效;