JavascriptLoser
JavascriptLoser

Reputation: 1962

Check if a point lies within an axis-aligned rectangle efficiently as possible, including the edge?

I am working on an interactive web application, and I'm currently working on implementing a multi-select feature similar to the way windows allows you to select multiple desktop icons by dragging a rectangle.

Due to limitations of the library I'm required to use, implementing this has already become quite resource intensive:

  1. On initial click, store the position of the mouse cursor.
  2. On each pixel that the mouse cursor moves, perform the following:

    1. Destroy the previous selection rectangle, if it exists, so it doesn't appear on the screen anymore.
    2. Calculate the width and height of the new selection retangle using the current cursor position and the current cursor position.

    3. Create a new selection rectangle using the original cursor position, the width and the height

    4. Display this rectangle on the screen

As you can see, there are quite a few things happening every time the cursor moves a single pixel. I've looked into this as much as I can and there's no way I can make it any more efficient or any faster.

My next step is actually selecting the objects on the screen when the selection rectangle moves over them. I need to implement this algorithm myself so I have freedom to make it as efficient/fast as possible. What I need to do is iterate through the objects on the screen and check each one to see if it lies in the rectangle. So the loop here is going to consume more resources. So, I need the checking to be done as efficiently as possible.

Each object that can be selected can be represented by a single point, P(x, y).

How can I check if P(x, y) is within the rectangles I create in the fastest/most efficient way?

Here's the relevant information:

How can I achieve what I need to do as fast as possible?

Upvotes: 0

Views: 2074

Answers (2)

MBo
MBo

Reputation: 80187

Checking whether point P lies inside rectangle R is simple and fast
(in coordinate system with origin in the top left corner)

(P.X >= R.Left) and (P.X <= R.Right) and (P.Y >= R.Top) and (P.Y <= R.Bottom) 

(precalculate Right and Bottom coordinates of rectangle)

Perhaps you could accelerate overall algorithm if objects fulfill to some conditions, that allow don't check all the objects at every step.

Example: sort object list by X coordinate and check only those objects that lies in Left..Right range

More advanced approach: organize objects in some space-partitioning data structure like kd-tree and execute range search very fast

Upvotes: 2

EvilTak
EvilTak

Reputation: 7579

You can iterate through every object on screen and check whether it lies in the rectangle in a Cartesian coordinate system using the following condition:

p.x >= rect.left && p.x <= rect.right && p.y <= rect.top && p.y >= rect.bottom

If are going to have not more than 1000 points on screen, just use the naive O(n) method by iterating through each point. If you are completely sure that you need to optimize this further, read on.

Depending on the frequency of updating the points and number of points being updated each frame, you may want to use a different method potentially involving a data structure like Range Trees, or settle for the naive O(n) method.

  • If the points aren't going to move around much and are sparse (i.e. far apart from each other), you can use a Range Tree or similar for O(log n) checks. Bear in mind though that updating such a spatial partitioning structure is resource intensive, and if you have a lot of points that are going to be moving around quite a bit, you may want to look at something else.

  • If a few points are going to be moving around over large distances, you may want to look at partitioning the screen into a grid of "buckets", and check only those buckets that are contained by the rectangle. Whenever a point moves from one bucket to another, the grid will have to update the affected buckets.

    • If memory is a constraint, you may want to look at using a modified Quad Tree which is limited by tree depth instead of bucket size, if the grid approach is not efficient enough.

If you have a lot of points moving around a lot every frame, I think you may be better of with the grid approach or just with the naive O(n) approach. Experiment and choose an approach that best suites your problem.

Upvotes: 0

Related Questions