Optimization of Rectangle-based Point Search

104 views Asked by At

I have a set of rooms and passages that I can convert into Rectangles (x,y,width,height) or a list of Points (x,y). Room and Passage both extend the Pointable interface. The getPoints() method is implemented for the Room class as

public Set<Point> getPoints() {
    Set<Point> array = new HashSet<Point>();
    for (int i = 0; i < width; i++) {
        for (int j = 0; j < height; j++) {
            array.add(new Point(x + i, y + j));
        }
    }
    return array;
}


The Problem:
I must identify the Pointable that a given Point belongs to. No rooms intersect. I originally used a HashMap<Point,Pointable> to correlate each Point to a Pointable, which was able to quickly able to access the answer in O(n) time. However, it is now necessary to recalculate the HashMap multiple times in the generation of a level.

At this point, is it still more efficient to use the HashMap (in consideration of generation and access) or should another method be used, such as a set of 2-D interval trees?

1

There are 1 answers

0
maaartinus On BEST ANSWER

At this point, is it still more efficient to use the HashMap (in consideration of generation and access) or should another method be used, such as a set of 2-D interval trees?

Nobody can tell except the one who did a measurement. It all depends on how often you need to update the data, how often they change, and how often they get queried.

And also on the size of a Room. With a few points, the HashMap wins in a typical scenario, with thousands of them, the overhead of updating the points dominates.


Can't you use an array for all Points? If so, then it'll be surely way faster then the HashMap, especially for updating (unless it gets really huge).


This may or may not be useful.

Actually, not only each Room has some Points, but also each Point may have one Room (n:1). How it gets implemented, it's a different question.

Given this, we have a standard problem: If you link bidirectionally, then you have to keep both links in sync. The simplest solution is to make the setters ("adders"/"removers") as private as possible and only called them from a method

void link(Room room, Point point) {
    Room oldRoom = point.getRoom();
    if (oldRoom!=null) oldRoom.removePoint(point);
    room.addPoint(point);
    point.setRoom(room);
}

Your linking from Point to Room is external, but this hardly changes anything (except for keeping Point smaller and possibly cleaner and adding the tiny overhead of a HashMap to each access).

It's usually also the fastest as usually there are much more queries than updates. Your problem is that the update cost gets scaled up by the Room size. Without you telling us some figures, no estimate is possible.


With too many points and rooms of not too widely varying size, you could round the point coordinates to a multiple of some n and keep an array holding the set of all rooms intersecting the grid. You could proceed as before, but the update overhead would be lower by nearly a factor given by the room area(*) and the search overhead higher, as you'd have to select the really matching room (if any) from the set.

(*) For rooms not aligned to grid, the number of intersecting rectangles is obviously higher.