问题
I have an image, and I want to show tooltips when mouse moves over certain rectangular areas. The rectangular areas can be up to 1000. However, just checking each rectangle if the point is in it, which is O(N), makes the interface unresponsive when moving the mouse.
Is there a way to do it in less than O(N)? I can sort the rectangles beforehand (I'm assuming it would be needed). The rectangles might be (very rarely) overlapping, but no more than 4-5 rectangles can overlap the same area. In that case I might need to get a list of all the rectangles, but even just any of them would still be good enough.
But I'm assuming that this problem has already been solved by window managers, etc.
回答1:
It sounds like you want to be storing your rectangles within an R-Tree and then querying that. There are a few implementations available:
- JTS Topology Suite (Java)
- Net Topology Suite (.Net)
- GeoTools (.Net)
Check out their STRtree classes.
回答2:
A faster and simpler (though less memory efficient) method than a tree for images (and web pages that can be rendered onto reasonably small images) is to use a stencil. i.e. if you have an image of x by y pixels, create a two dimensional array of size x by y and populate it with your tool tip IDs. This has a search speed from pixel position to ID of O(1) (my favourite O)
回答3:
If the rectangle are axis-aligned, you can avoid specialised data structures.
First subdivide the space in one dimension, e.g. subdividing the screen horizontally into vertical strips. Each rectangle may be in multiple strips. Then you subdivide each strip depending on the rectangles that overlap that strip. The search then involves two O(log n) binary searches or binary trees - one to identify the strip, one to identify which rectangle.
This is a recognised spatial data structure, but to me it doesn't really count - it's just using normal binary trees. You could even do it with an std::map<int, std::map<int, int>>
.
But there's actually an option supporting O(1) searches, which is called "pixel picking". Basically, draw the rectangles in an off-screen bitmap, each rectangle in a different colour, and frontmost rectangles last as you would for normal drawing (painters algorithm). You can identify which rectangle is frontmost at any point by simply reading that pixel.
Extra bonus - your graphics card may even accelerate drawing the rectangles, so you don't need to worry too much about redrawing when the set of rectangles changes (which obviously isn't included in that O(1)). It's a bit expensive in memory but, on a modern machine, you may not care about that.
回答4:
Use a spatial search data structure such as the quad-tree.
You will need to add your rectangles to the tree beforehand, but the average search will be fast. In the worst case you may still have O(N) though.
来源:https://stackoverflow.com/questions/16583908/find-out-if-point-is-inside-one-of-n-possibly-overlapping-rectangles-in-less-t