地图上最近的点

发布于 2024-11-30 07:41:27 字数 757 浏览 0 评论 0原文

我正在制作一个程序,您可以单击地图来查看其周围区域的“特写视图”,例如在 Google 地图上。

当用户单击地图时,它会获取他们单击位置的 X 和 Y 坐标。

假设我有一个布尔值数组,表示这些特写视图图片的位置:

public static boolean[][] view_set=new boolean[Map.width][Map.height];
//The array of where pictures are.  The map has a width of 3313, and a height of 3329.

程序搜索一个文件夹,其中图像以地图上拍摄位置的 X 和 Y 坐标命名。该文件夹包含以下图像(以及更多图像,但我只列出五个):

2377,1881.jpg, 2384,1980.jpg, 2389,1923.jpg, 2425,1860.jpg, 2475,1900.jpg

这意味着:

view_set[2377][1881]=true;
view_set[2384][1980]=true;
view_set[2389][1923]=true;
view_set[2425][1860]=true;
view_set[2475][1900]=true;

如果用户单击 X 和 Y,例如 2377,1882,那么我需要程序找出哪个image 最接近(本例中的答案是 2377,1881)。

任何帮助将不胜感激, 谢谢。

I am making a program where you can click on a map to see a "close-up view" of the area around it, such as on Google Maps.

When a user clicks on the map, it gets the X and Y coordinate of where they clicked.

Let's assume that I have an array of booleans of where these close-up view pictures are:

public static boolean[][] view_set=new boolean[Map.width][Map.height];
//The array of where pictures are.  The map has a width of 3313, and a height of 3329.

The program searches through a folder, where images are named to where the X and Y coordinate of where it was taken on the map. The folder contains the following images (and more, but I'll only list five):

2377,1881.jpg, 2384,1980.jpg, 2389,1923.jpg, 2425,1860.jpg, 2475,1900.jpg

This means that:

view_set[2377][1881]=true;
view_set[2384][1980]=true;
view_set[2389][1923]=true;
view_set[2425][1860]=true;
view_set[2475][1900]=true;

If a user clicks at the X and Y of, for example, 2377,1882, then I need the program to figure out which image is closest (the answer in this case would be 2377,1881).

Any help would be appreciated,
Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

空城仅有旧梦在 2024-12-07 07:41:27

对于这个问题,您的 boolean[][] 不是一个好的数据结构,至少如果它不是非常密集的话(例如,通常在周围 3×3 或可能有一个具有特写视图的点) 5×5 正方形)。

您需要一个具有最近邻搜索功能的二维地图。对于此目标来说,一个有用的数据结构是QuadTree。这是一棵4度树,用于表示空间数据。 (我在这里描述的是“带有点数据的区域四叉树”。)

基本上,它将一个矩形分成四个大小相等的矩形,并进一步细分每个矩形如果其中有多个点。

因此,树中的节点是以下之一:

  • 空叶节点(对应于其中没有点的矩形)
  • 只包含一个点的叶节点(对应于其中有一个点的矩形)
  • 具有四个子节点的内部节点(对应于其中有多个点的矩形)

(在实现中,我们可以用其父节点中的空指针替换空叶节点。)

要找到一个点(或“点所在的节点”),我们从根源开始节点,查看我们的点是否在分界点的北/南/东/西,并转到对应的子节点。我们继续这个直到到达某个叶节点。

  • 为了添加新点,我们要么得到一个空节点 - 然后我们可以将新点放在这里。如果我们最终到达一个已经有一个点的节点,请创建四个子节点(通过分割矩形)并将这两个点添加到适当的子节点。 (这可能是相同的,然后递归地重复。)

  • 对于最近邻搜索,我们要么得到一个空节点 - 然后我们备份一个级别,并查看该父节点的其他子节点(比较每个距离)。如果我们到达其中有一个点的子节点,我们将测量搜索点到该点的距离。如果它小于到边或节点的距离,我们就完成了。否则,我们还必须查看相邻节点中的点,并比较这里的结果,取最小值。 (我认为,我们最多必须查看四个点。)

  • 为了删除,找到一个点后,我们将其节点设为空。如果父节点现在只包含一个点,我们将其替换为单点叶节点。

搜索和添加/删除的时间复杂度为 O(深度),其中最大深度受到 log((地图长度+宽度)/结构中两点的最小距离) 和平均值的限制深度或多或少取决于点的分布(例如到下一个点的平均距离)。

所需的空间取决于点的数量和树的平均深度。

这种数据结构有一些变体(例如,仅当节点中有超过 X 个点时才拆分节点,或者不一定在中间拆分),以优化空间使用并避免树的深度过大。

Your boolean[][] is not a good datastructure for this problem, at least if it is not really dense (e.g. normally a point with close-up view is available in the surrounding 3×3 or maybe 5×5 square).

You want a 2-D-map with nearest-neighbor search. A useful data structure for this goal is the QuadTree. This is a tree of degree 4, used to represent spatial data. (I'm describing here the "Region QuadTree with point data".)

Basically, it divides a rectangle in four about equal size rectangles, and subdivides each of the rectangles further if there is more than one point in it.

So a node in your tree is one of these:

  • a empty leaf node (corresponding to a rectangle without points in it)
  • a leaf node containing exactly one point (corresponding to a rectangle with one point in it)
  • a inner node with four child nodes (corresponding to a rectangle with more than one point in it)

(In implementations, we can replace empty leaf nodes with a null-pointer in its parent.)

To find a point (or "the node a point would be in"), we start at the root node, look if our point is north/south/east/west of the dividing point, and go to the corresponding child node. We continue this until we arrive at some leaf node.

  • For adding a new point, we either wind up with an empty node - then we can put the new point here. If we end up at a node with already a point in it, create four child nodes (by splitting the rectangle) and add both points to the appropriate child node. (This might be the same, then repeat recursively.)

  • For the nearest-neighbor search, we will either wind up with an empty node - then we back up one level, and look at the other child nodes of this parent (comparing each distance). If we reach a child node with one point in it, we measure the distance of our search point to this point. If it is smaller than the distance to the edges or the node, we are done. Otherwise we will have to look at the points in the neighboring nodes, too, and compare the results here, taking the minimum. (We will have to look at at most four points, I think.)

  • For removal, after finding a point, we make its node empty. If the parent node now contains only one point, we replace it by a one-point leaf node.

The search and adding/removing are in O(depth) time complexity, where the maximum depth is limited by log((map length+width)/minimal distance of two points in your structure), and average depth is depending on the distribution of the points (e.g. the average distance to the next point), more or less.

Space needed is depending on number of points and average depth of the tree.

There are some variants of this data structure (for example splitting a node only when there are more than X points in it, or splitting not necessarily in the middle), to optimize the space usage and avoid too large depths of the tree.

千里故人稀 2024-12-07 07:41:27

给定用户单击的位置,您可以使用 Dijkstra 搜索来搜索最近的图像。
基本上,您开始在单击位置周围越来越大的矩形中搜索图像。当然,您只需要搜索这些矩形的边界,因为您已经搜索了主体。一旦找到图像,该算法就应该停止。

伪代码:

int size = 0
Point result = default
while(result == default)
   result = searchRectangleBoundary(size++, pointClicked)

function Point searchRectangleBoundary(int size, Point centre)
{
    point p = {centre.X - size, centre.Y - size}
    for i in 0 to and including size
    {
        if(view_set[p.X + i][p.Y]) return { p.X + i, p.Y}
        if(view_set[p.X][p.Y + i]) return { p.X, p.Y + i}
        if(view_set[p.X + i][p.Y + size]) return { p.X + i, p.Y + size}
        if(view_set[p.X + size][p.Y + i]) return { p.X + size, p.Y + i}
    }
    return default
}

请注意,为了简洁起见,我省略了范围检查。

有一个小问题,但根据应用程序,这可能不是问题。它不使用欧几里得距离,而是使用曼哈顿距离。所以它不一定能找到最近的图像,而是最多找到 2 倍远的平方根的图像。

Given the location the user clicked, you could search for the nearest image using a Dijkstra search.
Basically you start searching in increasingly larger rectangles around the clicked location for images. Of course you only have to search the boundaries of these rectangles, since you've already searched the body. This algorithm should stop as soon as an image is found.

Pseudo code:

int size = 0
Point result = default
while(result == default)
   result = searchRectangleBoundary(size++, pointClicked)

function Point searchRectangleBoundary(int size, Point centre)
{
    point p = {centre.X - size, centre.Y - size}
    for i in 0 to and including size
    {
        if(view_set[p.X + i][p.Y]) return { p.X + i, p.Y}
        if(view_set[p.X][p.Y + i]) return { p.X, p.Y + i}
        if(view_set[p.X + i][p.Y + size]) return { p.X + i, p.Y + size}
        if(view_set[p.X + size][p.Y + i]) return { p.X + size, p.Y + i}
    }
    return default
}

Do note that I've left out range checking for brevity.

There is a slight problem, but depending on the application, it might not be a problem. It doesn't use euclidian distances, but the manhattan metric. So it doesn't necessarily find the closest image, but an image at most the square root of 2 times as far.

水晶透心 2024-12-07 07:41:27

根据

  • 您的评论,您有 350-500 个兴趣点,
  • 您的问题表明您的地图宽度为 3313,高度为 3329
    • 我的计算器告诉我这代表大约 1100 万个布尔值

……你的处理方式是错误的。 @JBSnorro 的答案是一种在大海捞针(1100 万点)中找到针(350 点)的相当优雅的方法,但实际上,为什么首先要创建大海捞针呢?

根据我对您问题的评论,为什么不只使用 Pair类来表示坐标,将它们存储在一个集合中,然后扫描它们?它更简单、更快、消耗更少的内存,并且对于更大的地图来说更具可扩展性(假设兴趣点稀疏......鉴于它们是兴趣点,这似乎是一个明智的假设) )。

..相信我,计算欧几里得距离约 425 次,比在 1100 万个值 boolean[][] 中徘徊寻找 25,950 中感兴趣的 1 值(尤其是在最坏情况分析中)要快得多。 。


如果您真的对每次扫描约 425 个值的想法不感兴趣,那么 (i) 您比我更强迫症 (:P); (ii) 您应该查看最近邻居搜索算法。

Based on

  • your comment that states you have 350-500 points of interest,
  • your question that states you have a map width of 3313, and a height of 3329
    • my calculator which tells me that that represents ~11 million boolean values

...you're going about this the wrong way. @JBSnorro's answer is quite an elegant way of finding the needle (350 points) in the haystack (11 million points), but really, why create the haystack in the first place?

As per my comment on your question, why not just use a Pair<Integer,Integer> class to represent co-ordinates, store them in a set, and scan them? It's simpler, quicker, less memory consuming, and is way more scalable for larger maps (assuming the points of interest are sparse... which it seems is a sensible assumption given that they're points of interest).

..trust me, computing the Euclidean distance ~425 times beats wandering around an 11 million value boolean[][] looking for the 1 value in 25,950 that's of interest (esp. in a worst case analysis).


If you're really not thrilled with the idea of scanning ~425 values each time, then (i) you're more OCD than me (:P); (ii) you should check out nearest neighbour search algorithms.

一曲琵琶半遮面シ 2024-12-07 07:41:27

我不知道你是否有这个要求。如果用户点是P1{x1,y1}并且你想计算它到P2{x2,y2}的距离,则使用毕达哥拉斯定理计算距离

distance^2 = (x2-x1)^2 + (y2-y1)^2

如果你只想知道最近的,可以避免计算平方根(距离越小,正方形也越小,所以它对你来说是一样的)。

I do not know if you are asking for this. If the user point is P1 {x1, y1} and you want to calculate its distance to P2 {x2,y2}, the distance is calculated using Pythagoras'Theorem

distance^2 = (x2-x1)^2 + (y2-y1)^2

If you only want to know the closest, you can avoid calculating the square root (the smaller the distance, the smaller the square too so it serves you the same).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文