ST_Contains在MySQL中返回不准确结果的原因是什么?

huangapple go评论51阅读模式
英文:

Why does ST_Contains in MySQL return inaccurate results?

问题

我正在尝试通过向MySQL表'location'添加一个带有SPATIAL索引的POINT列(SRID 4326)来加速选择位置。但尽管速度更快,但似乎会产生不准确的结果。

位置表包括id(主键),名称,纬度,经度和新添加的latlon列。后者是使用ST_GeomFromText(concat("POINT(",latitude," ",longitude,")"), 4326)计算的。

在旧情况下,我使用以下查询来获取特定区域的位置。例如,纬度在15和69之间,经度在-78和84之间:

SELECT * FROM `location` WHERE (latitude BETWEEN 15 AND 69) AND (longitude BETWEEN -78 AND 84)

在新情况下,我会像这样检查点和多边形的交集:

SELECT * FROM location 
WHERE (ST_CONTAINS(
ST_GeomFromText('POLYGON((69 -78, 69 84, 15 84, 15 -78, 69 -78))', 4326), latlon))

(多边形从西北到东北,东南,西南,再到西北)

我期望获得相同的结果,但它们是不同的。点和多边形的方法始终返回较少的结果。在这个示例中,前者返回18365个结果,而后者只有6961个。

为了检查差异,我运行了这个查询:

SELECT id,name,latitude,longitude,
(ST_CONTAINS(
ST_GeomFromText('POLYGON((69 -78, 69 84, 15 84, 15 -78, 69 -78))', 4326), latlon)) AS contains 
FROM `location` 
WHERE (latitude BETWEEN 15 AND 69) AND (longitude BETWEEN -78 AND 84)

其中一些结果如下(5个包含和5个不包含):

Id Name Latitude Longitude Contains
53VA Horse Feathers Airport 38.634 -77.7575 1
84VA Cia Headquarters Heliport 38.9529 -77.1525 1
GQPZ Tazadit Airport 22.75735 -12.48223 0
LENF Monforte De Lemos 42.54694 -7.51917 0
LIAY La Bagnara 41.68722 13.49917 0
LTCK Muş Airport 38.7478 41.6612 0
LW68 Srpci Airfield 41.15173 21.40687 0
PA71 Dwight's Delight Airport 41.5209 -76.4622 1
RI16 Keskinen Balloonport 41.71991 -71.6316 1
VA79 Hickory Tree Farms Airport 38.9529 -77.7469 1

误差似乎只在较小的矩形上出现;只有少数几个百分点的不准确,而不是近三分之一。

我无法弄清楚我在这里做错了什么。我还尝试使用ST_INTERSECT进行查询,或者使用8个点来定义更详细的多边形,而不是4个点来描述矩形。但这些都没有帮助。

我在这里忽略了什么?

英文:

I'm trying to speed up the selection of locations from a MySQL table 'location' by adding a POINT column (SRID 4326) with a SPATIAL index. But although it's faster, it seems to produce inaccurate results.

The location table has an id (primary key), name, latitude, longitude and newly added latlon column. The latter calculated with ST_GeomFromText(concat("POINT(",latitude," ",longitude,")"), 4326)

CREATE TABLE `location` (
   `id` varchar(16) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
   `name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
   `latitude` decimal(10,5) DEFAULT NULL,
   `longitude` decimal(10,5) DEFAULT NULL,
   `latlon` point SRID 4326 NOT NULL
) ;

I used to get locations in a certain area with this query. For example latitudes between 15 and 69 and longitudes between -78 and 84

SELECT * FROM `location` WHERE (latitude BETWEEN 15 AND 69) AND (longitude BETWEEN -78 AND 84)

In the new situation I would check for a point-in-polygon intersection like this:

SELECT * FROM location 
WHERE (ST_CONTAINS(
ST_GeomFromText('POLYGON((69 -78, 69 84, 15 84, 15 -78, 69 -78))', 4326), latlon))

(polygon from northwest -> northeast -> southeast -> southwest -> northwest)

I would expect to get the same results, but they are different. The point-in-polygon method always returns less results. In this example the first would return 18365 results and the latter only 6961.

To check the differences I ran this query:

SELECT id,name,latitude,longitude,
(ST_CONTAINS(
ST_GeomFromText('POLYGON((69 -78, 69 84, 15 84, 15 -78, 69 -78))', 4326), latlon)) AS contains 
FROM `location` 
WHERE (latitude BETWEEN 15 AND 69) AND (longitude BETWEEN -78 AND 84) 

Some of it's results as an example (5 contained and 5 not contained):

Id Name Latitude Longitude Contains
53VA Horse Feathers Airport 38.634 -77.7575 1
84VA Cia Headquarters Heliport 38.9529 -77.1525 1
GQPZ Tazadit Airport 22.75735 -12.48223 0
LENF Monforte De Lemos 42.54694 -7.51917 0
LIAY La Bagnara 41.68722 13.49917 0
LTCK Muş Airport 38.7478 41.6612 0
LW68 Srpci Airfield 41.15173 21.40687 0
PA71 Dwight's Delight Airport 41.5209 -76.4622 1
RI16 Keskinen Balloonport 41.71991 -71.6316 1
VA79 Hickory Tree Farms Airport 38.9529 -77.7469 1

The error seems only marginal with a smaller rectangle; only a few percent inaccurate instead of almost a third.

I can't figure out what I'm doing wrong here. Also tried to query using ST_INTERSECT, or defining a more detailed polygon with 8 points describing the rectangle instead of 4. None of this helped.

What am I overlooking here?

答案1

得分: 1

只有你的多边形只有4个角,连接它们的线将是直线而不是大圆线,所以你的一些点将无法包含在多边形中。

这张图片展示了这个问题 - 你正在使用紫色的框,而世界正在使用黄色的框。

你可能希望增加多边形的边缘密度,使其遵循地球的曲率 - 我不是一个MySql用户,但在PostGIS中,我会使用STDensify

英文:

Since your polygon only has 4 corners the lines joining them will be straight rather than great circles so some of your points will fail to be included in the polygon.

ST_Contains在MySQL中返回不准确结果的原因是什么?

This picture shows the issue - you are using the purple box while the world uses the yellow one.

You probably want to densify the edges of your polygon to make it follow the curvature of the earth - I'm not a MySql user but in PostGIS I'd use STDensify.

huangapple
  • 本文由 发表于 2023年4月7日 00:40:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/75951857.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定