在特定范围内获取X/Y坐标的正确数据,但包括宽度和高度

4

我正在编写雷达逻辑,用于找到附近的物体并在“雷达”窗口中显示它们,如下所示:

enter image description here

这个逻辑(行得通!)如下所示 - 稍微简化了原始版本:
 -- 5000 = radar distance
 -- Width can be called from a.width
 -- Height can be called from a.height

.

select * from positions a
    inner join positions b on b.user_id = :user_id
    left join users u on a.user_id = u.id
where 1=1
and (
    a.x >= (b.x - 5000)
 && a.x <= (b.x + 5000)
 && a.y >= (b.y - 5000)
 && a.y <= (b.y + 5000)
)

我遇到的问题是一些物体非常大,甚至比雷达距离还大。这意味着,如果大物体的中心点超出了雷达距离,整个物体就会消失,即使它的高度/宽度仍在雷达范围内。以下是一个示例问题(向左移动导致黄色形状消失,即使它仍然在雷达视野范围内,但对象的中心点已经超出了雷达距离,因此未在sql结果中显示)。

enter image description here

我希望我已经解释得足够清楚,让人们能够理解。以下是我自己尝试解决这个问题的尝试(没有一个成功的):

失败尝试#1:

select * from positions a
    inner join positions b on b.user_id = 10
    left join users u on a.user_id = u.id
where 1=1
and (
    a.x >= ((b.x+a.width) - 5000)
 && a.x <= ((b.x-a.width) + 5000)
 && a.y >= ((b.y+a.height) - 5000)
 && a.y <= ((b.y+a.height) + 5000)
)

失败尝试 #2:

select * from positions a
    inner join positions b on b.user_id = 10
    left join users u on a.user_id = u.id
where 1=1
and (
    a.x >= (b.x - 5000)
 && a.x <= (b.x + 5000)
 && a.y >= (b.y - 5000)
 && a.y <= (b.y + 5000)
)
OR (
    (a.x+a.width) >= ((b.x+a.width) - 5000)
 && (a.x-a.width) <= ((b.x-a.width) + 5000)
 && (a.y+a.height) >= ((b.y+a.height) - 5000)
 && (a.y-a.height) <= ((b.y+a.height) + 5000)
)

我觉得我已经到了开始混淆自己的地步。如果您需要任何额外的信息,请告诉我。 感谢考虑我的问题。

更详细的示例:

每个对象都有高度/宽度/x/y坐标,如下所示:

+----+------+------+--------+-------+
| id |  x   |  y   | height | width |
+----+------+------+--------+-------+
|  1 |  100 |  100 |    150 |   150 |
|  2 | -250 |  500 |    150 |   150 |
|  3 | 5000 | 2000 |  10000 | 10000 |
+----+------+------+--------+-------+

假设有一个任意的“雷达距离”设置为5,000。
如果我坐在坐标:0x,0y,我可以看到ID3。如果我移动到坐标:-100x,0y,我的SQL将不再检索ID3,因为坐标的中心点扩展到了5,000雷达距离之外。然而-宽度向雷达的50%扩展,高度向雷达的50%扩展,这意味着对象仍应通过SQL被看到和检索。 SQL Fiddle(将-100更改为0,您将再次在返回的数据中看到大对象)

你基本上想要返回所有在圆形(雷达在2D中的有效范围)和你数据库中任何2D对象的交集中的对象。这正是mysql / mariadb的地理空间扩展所用之处。你考虑过使用这个扩展吗? - Shadow
嗨Shadow,谢谢你的回复,但很抱歉我无法使用任何扩展来解决这个问题。雷达距离实际上是一个正方形相交,黄色形状也是一个正方形,只是设置了边框半径。我仍在尝试使用纯SQL逻辑解决这个问题。干杯 - Jack
空间扩展已经内置于mysql/mariadb中。如果您安装了正确的版本,则可以使用这些函数。由于这些函数和数据类型是mysql和mariadb的一部分,因此使用它们意味着使用纯SQL逻辑。 - Shadow
谢谢你转发给我,我现在正在尝试阅读文档。 - Jack
@Strawberry 正如我在问题开头已经说明的那样,我为了这个问题简化了查询。我的原始查询显然不是 Select *。SQL Fiddle 应该足以让人们继续进行,即使使用 *,本问题中的所有查询仍然按预期工作。 - Jack
3个回答

1

好的,我想我已经找到了我的问题的答案。我认为这个做法可以:

set @my_x = -100;
set @my_y = 0;
set @radar_distance = 5000;

select * from positions a
where 1=1
and (
    a.x >= (@my_x - @radar_distance)
 && a.x <= (@my_x + @radar_distance)
 && a.y >= (@my_y - @radar_distance)
 && a.y <= (@my_y + @radar_distance)
)
or (
    a.x+(a.width/2) >= (@my_x - @radar_distance)
 && a.x-(a.width/2) <= (@my_x + @radar_distance)
 && a.y+(a.height/2) >= (@my_y - @radar_distance)
 && a.y-(a.height/2) <= (@my_y + @radar_distance)
)

尽管我认为,如果物体的尺寸比雷达更长,它仍然会破裂。我现在将进行测试。
是的,这有效。
我还认为我可以在我的OR之前将整个第一个条件块删除。需要测试。 SQL Fiddle

1
从概念上讲,您需要根据可能在窗口中可见的对象的大小扩展搜索区域窗口,即基本窗口大小+-对象宽度的一半,并查看对象的中心点是否在此动态大小的窗口中。 - Caius Jard

0

你所说的“宽度”和“高度”听起来像是图形距离的“边界框”方法。你是否也像danblack建议的那样使用勾股距离?

实际上,你有两个宽度和高度(或两个半径)——一个用于雷达延伸的距离,一个用于每个物体延伸的距离。类似这样:

 AND a.x >= ((b.x+a.width) - (5000 + b.width))
 AND a.x <= ((b.x-a.width) + (5000 + b.width))
 AND a.y >= ((b.y+a.height) - (5000 + b.height))
 AND a.y <= ((b.y+a.height) + (5000 + b.height))

这意味着每个对象都有一个高度宽度(以及半径)。

嗨Rick,我有点困惑你的确切意思是什么。当我添加那个例子时,我想有点困惑,对此感到抱歉。我已经添加了一个SQL Fiddle,希望更详细地显示问题。是的,你说得对,宽度和高度就像对象的“边界框”,而x/y则是该对象的精确中心。我尝试了丹的答案,但似乎没有考虑到宽度/高度。 - Jack

0

适当使用方形限制可以限制数据范围,但从一个点的距离应该是主要的 SQL 条件。

SELECT * FROM positions a
INNER JOIN positions b ON b.user_id = 10
WHERE POW(a.x - b.x, 2) + POW(a.y - b.y, 2) < POW(5000,2);

嗨,丹 - 这个版本似乎模仿了原始代码,但也存在相同的问题,即它不包括高度/宽度扩展到雷达区域的数据(如果有意义的话!)顺便说一句,帽子很漂亮! - Jack

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接