我有一个具有x,y,宽度和高度的矩形对象。我有这些在屏幕上显示的矩形的列表。保证它们没有重叠。给定用户的单击位置(x和y坐标),我想查看这些矩形中的哪个被单击了(由于它们不重叠,因此最多可以单击一个矩形)。
很明显,我可以查看所有这些内容,并检查是否单击了用户,但是这很慢,因为屏幕上有很多内容。当我在列表中插入新矩形时,可以使用某种比较方法来使矩形保持排序。是否有某种方法可以使用类似于二进制搜索的方法,以减少找到单击哪个矩形所需的时间?
注意:矩形可以是任何大小。 谢谢:)
编辑:要了解我在做什么,请访问koalastothemax.com
答案 0 :(得分:1)
这在很大程度上取决于您的应用程序和详细信息,我们尚不了解最佳解决方案是什么。但是,据我所知,我想说的是,您可以制作一个指向矩形的2D数组。该2D阵列将直接映射到屏幕上的像素。因此,如果将数组设置为10x20,则坐标x除以屏幕宽度乘以10(投射到int)将成为第一个索引,而y除以屏幕高度乘以20将成为您的y索引。使用x和y索引,您可以直接映射到它所指向的矩形。如果索引布局不正确,有些索引可能为空,有些索引可能指向多个矩形,但这对我来说似乎是最简单的方法,而无需对应用程序了解太多。
答案 1 :(得分:0)
我想出的最快方法绝对不是最有效的内存。这通过利用摊销哈希表具有恒定查找时间这一事实而起作用。它将映射矩形所具有的每个点。仅当您使用整数时,这才真正有效。如果您使用四舍五入,则可以使它与浮点数一起使用。
确保Point
类具有哈希码和equals函数。
public class PointCheck
{
public Map<Point, Rect> pointMap;
public PointCheck()
{
pointMap = new HashMap<>();
}
/**
* Map all points that contain the rectangle
* to the rectangle.
*/
public void addRect(Rect rect)
{
for(int i = rect.x; i < rect.x + rect.width; ++i)
{
for(int j = rect.y; j < rect.y + rect.height; ++i)
{
pointMap.put(new Point(i, j), rect);
}
}
}
/**
* Returns the rectangle clicked, null
* if there is no rectangle.
*/
public Rect checkClick(Point click)
{
return pointMap.get(click);
}
}
编辑: 只是想我应该提一下:哈希表值中保存的所有矩形都是对原始矩形的引用,不是克隆。
答案 2 :(得分:0)
过去,在开发模拟时,我已经解决了一个非常相似的问题。在我的情况下,坐标是双精度的(因此不可能进行整数索引),并且可能有数亿个坐标需要搜索。
我的解决方案是创建一个Axis
类,以将每个轴表示为一系列范围。保证范围从最小到最大,并且班级足够聪明,可以在添加新范围时将自身拆分为多个部分。每个范围都存储了一个通用对象。该课程使用二进制搜索来快速找到范围。
因此,该类大致如下:
class Axis<T> {
public Axis(double min, double max, Supplier<T> creator);
public Stream<T> add(double from, double to);
public T get(double coord);
}
add
方法需要返回流,因为添加的范围可能涵盖多个范围。
要存储矩形:
Axis<Axis<Rectangle>> rectanges = new Axis<>(0.0, 100.0,
() -> new Axis<>(0.0, 100.0, Rectangle::new));
rectangles.add(x, x + w).forEach(r -> r.add(y, y + h).forEach(Rectangle::setPresent));
并找到一个矩形:
rectangles.get(x).get(y);
请注意,始终会存储一个对象,因此您需要使用诸如Rectangle.NULL
之类的表示形式来表示“不存在”。或者,您可以将其设置为Optional<Rectangle>
(尽管这种间接操作会占用大量内存并处理大量矩形)。
我只是在这里提供了高级设计,而不是任何实现细节,因此,如果您需要更多有关如何使其工作的信息,请告诉我。在范围划分上正确掌握逻辑并非易事。但是我可以保证,即使有大量矩形,它也非常快。