Thursday, May 21, 2015

c# - How do I efficiently check if a point is inside a rotated rectangle?


Part for the sake of optimization, part for learning purposes, I will dare to ask: How can I most efficiently check whether a 2D point P is inside a 2D rotated rectangle XYZW, using C# or C++?


Currently, what I am doing is using a "point in triangle" algorithm found in the book Real Time Collision Detection, and running it twice (for the two triangles that make up the rectangle, say XYZ and XZW):


bool PointInTriangle(Vector2 A, Vector2 B, Vector2 C, Vector2 P)
{
// Compute vectors
Vector2 v0 = C - A;

Vector2 v1 = B - A;
Vector2 v2 = P - A;

// Compute dot products
float dot00 = Vector2.Dot(v0, v0);
float dot01 = Vector2.Dot(v0, v1);
float dot02 = Vector2.Dot(v0, v2);
float dot11 = Vector2.Dot(v1, v1);
float dot12 = Vector2.Dot(v1, v2);


// Compute barycentric coordinates
float invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
float u = (dot11 * dot02 - dot01 * dot12) * invDenom;
float v = (dot00 * dot12 - dot01 * dot02) * invDenom;

// Check if point is in triangle
if(u >= 0 && v >= 0 && (u + v) < 1)
{ return true; } else { return false; }
}



bool PointInRectangle(Vector2 X, Vector2 Y, Vector2 Z, Vector2 W, Vector2 P)
{
if(PointInTriangle(X,Y,Z,P)) return true;
if(PointInTriangle(X,Z,W,P)) return true;
return false;
}

However, I have the feeling that there might be a cleaner and faster way. Specifically, to reduce the number of math operations.



Answer




An easy and straightforward optimization would be to change the final condition in PointInTriangle:


bool PointInRectangle(Vector2 A, Vector2 B, Vector2 C, Vector2 P) {
...
if(u >= 0 && v >= 0 && u <= 1 && v <= 1)
{ return true; } else { return false; }
}
}

the code was pretty much PointInRectangle already, the condition (u + v) < 1 was there to check if it is not in the "second" triangle of rectangle.


Alternatively, you could also do an isLeft (first code example on page, also greatly explained) test four times, and check that they all return results with the same sign (which one depends on whether the points were given in clockwise or counterclockwise order) for the point to be inside. This works for any other convex polygon too.



float isLeft( Point P0, Point P1, Point P2 )
{
return ( (P1.x - P0.x) * (P2.y - P0.y) - (P2.x - P0.x) * (P1.y - P0.y) );
}
bool PointInRectangle(Vector2 X, Vector2 Y, Vector2 Z, Vector2 W, Vector2 P)
{
return (isLeft(X, Y, P) > 0 && isLeft(Y, Z, P) > 0 && isLeft(Z, W, P) > 0 && isLeft(W, X, p) > 0);
}

No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...