Given a center point, width, height and angle forming an OBB, how can I find if a given point P is inside the OBB?
Thanks
I take it that the wrinkle in your problem is that the bounding box can be rotated? If so, the easiest solution to me seems to be to do all calculations in the rotated coordinate plane, centered on the center of the bounding box.
To calculate the coordinates of the point relative to these axes:
newy = sin(angle) * (oldy - centery) + cos(angle) * (oldx - centerx);
newx = cos(angle) * (oldx - centerx) - sin(angle) * (oldy - centery);
(you may need to adjust this depending on how angle is supposed to be measured, I'll leave that to you, since you didn't specify)
Then hit test, the normal way:
return (newy > centery - height / 2) && (newy < centery + height / 2)
&& (newx > centerx - width / 2) && (newx < centerx + width / 2);
You could transform the coordinates of your test point (via a transformation matrix) into a rotated coordinate system based on the angle of the bounding box.
At this stage it should just be an axis-aligned point-in-rectangle test, i.e. compare against xmin, xmax, ymin, ymax. In the rotated coordinate system xmin, xmax = xmid -+ width/2 and ymin, ymax = ymid -+ height/2.
Hope this helps.
Related
I have trouble figuring out a way to detect collision between a circle and a rotated rectangle. My approach was to first rotate the circle and the rectangle by -angle, where angle is the amount of radians the rectangle is rotated. Therefore, the rectangle and the circle are aligned with the axes, so I can perform the basic circle - AABB collision detection.
bool CheckCollision(float circleX, float circleY, float radius, float left, float bottom, float width, float height, float angle){
// Rotating the circle and the rectangle with -angle
circleX = circleX * cos(-angle) - circleY * sin(-angle);
circleY = circleX * sin(-angle) + circleY * cos(-angle);
left = left * cos(-angle) - bottom* sin(-angle);
bottom = left * sin(-angle) + bottom * cos(-angle);
}
glm::vec2 center(circleX, circleY);
// calculate AABB info (center, half-extents)
glm::vec2 aabb_half_extents(width / 2.0f, height / 2.0f);
glm::vec2 aabb_center(
left + aabb_half_extents.x,
bottom + aabb_half_extents.y
);
// get difference vector between both centers
glm::vec2 difference = center - aabb_center;
glm::vec2 clamped = glm::clamp(difference, -aabb_half_extents, aabb_half_extents);
// add clamped value to AABB_center and we get the value of box closest to circle
glm::vec2 closest = aabb_center + clamped;
// retrieve vector between center circle and closest point AABB and check if length <= radius
difference = closest - center;
return glm::length(difference) < radius;
Let rectangle center is rcx, rcy. Set coordinate origin in this point and rotate circle center about this point (cx, cy are coordinates relative to rectangle center):
cx = (circleX - rcx) * cos(-angle) - (circleY - rcy) * sin(-angle);
cy = (circleX - rcx) * sin(-angle) + (circleY - rcy) * cos(-angle);
Now get squared distance from circle center to rectangle's closest point(zero denotes circle center is inside rectangle):
dx = max(Abs(cx) - rect_width / 2, 0)
dy = max(Abs(cy) - rect_height / 2, 0)
SquaredDistance = dx * dx + dy * dy
Then compare it with squared radius
I have circle with diameter 256px, middle point is on xy[128,128]. I have first point on circle, for example X=0,Y=128. Coordinates origin is in left top corner. Line between first point and middle, together with angle on this line (starting from middle) creates triangle which intersects circle in third point. How can I calculate this point?
Input variables are :
point xy on circle
middle point
angle
expected output is x1,y1
Formulas for rotation of initial point around center point by angle:
x1 = middle.x + (x - middle.x) * cos(angle) - (y - middle.y) * sin(angle)
y1 = middle.y + (x - middle.x) * sin(angle) + (y - middle.y) * cos(angle)
(this is affine transform - combination of translation middle to origin, rotation about origin and backward translation)
Don't forget to make cos and sin argument in radians rather than degrees like this:
cos(angle * M_PI / 180)
I've generated a geodesic sphere for opengl rendering following a question on here and I'm trying to put texture on it. I came up with the following code by reversing an algorithm for a point on a sphere:
//complete circle equation is as follows
///<Summary>
///x = r * sin(s) * sin(t)
///y = r* cos(t)
///z = r * cos(s) * sin(t)
///</Summary>
float radius = 1.0f;
//T (height/latitude) angle
float angleT = acos(point.y / radius) ;
//S (longitude )angle
float angleS = ( asin(point.x / (radius * sin(angleT)))) + (1.0f* M_PI);
float angleS2 =( acos(point.z / (radius * sin(angleT)))) + (1.0f * M_PI);
//Angle can be 0-PI (0-180 degs), divide by this to get 0-1
angleT = angleT / (M_PI);
//Angle can be 0-2PI (0-360 degs)S
angleS = angleS / ( M_PI *2 );
angleS2 = angleS2 / ( M_PI *2 );
//Flip the y co-ord
float yTex = 1 - angleT;
float xTex = 0.0f;
//I have found that angleS2 is valid 0.5-1.0, and angleS is valid (0.3-0.5)
if (angleS < 0.5f)
{
xTex = angleS;
}
else
{
xTex = angleS2;
}
return glm::vec2( xTex , yTex);
As you can see, I've found that both versions of calculating the S angle have limited valid ranges.
float angleS = ( asin(point.x / (radius * sin(angleT)))) + (1.0f* M_PI);
float angleS2 =( acos(point.z / (radius * sin(angleT)))) + (1.0f * M_PI);
S1 is gives valid answers between x texture co-ords 0.3 and 0.5 and S2 gives valid answers for between x texture co-ords 0.5 and 1.0 (Conversion to co-ords omitted above but present in first code example). Why is it that neither formula is giving me valid answers for under 0.3?
Thanks
Will
Correct on this side
The weird border between working and not, probably caused by opengl's interpolation
Reversed section
The image being used
Edit: Here is the seam
The equations you use to calculate the longitude angles are not correct seeing what you are trying to accomplish. For the longitude angle, the range you require is 0-360 degrees, which can not be obtained through asin or acos functions, because those functions only return results between -90 and 90 degrees or 0 to 180 degrees. You can, however, use the atan2 function, which returns values from the correct interval. The code I've been working with for the past 2 years is the following:
float longitude = atan2f(point.x, point.z) + (float)M_PI;
This equation will map the horizontal center of the texture in the direction of positive Z axis. If you want the horizontal center of the texture to be in the direction of positive X axis, add M_PI / 2.0.
Many of us are familiar with the approach to rotating a 2D vector around the origin given an angle theta:
newX = x * cos(theta) - y * sin(theta);
newY = x * sin(theta) + y * cos(theta);
I'm now trying to rotate coordinates in image UV space, which looks like this:
(Image borrowed from this SO question.)
Here the units of the u axis are wider than those of the v axis, so the approach above leads to the coordinates rotating around an ellipse as opposed to a circle. I need the rotation of the vector to act as though the coordinates were square, meaning the aspect ratio needs to be accounted for. I thought it'd be as simple as stretching the coordinates to a square space, rotating, then stretching back, although it still appears that the vectors are rotating elliptically:
newX = (x * cos(theta) * Aspect - y * sin(theta)) / Aspect;
newY = x * sin(theta) * Aspect + y * cos(theta);
Any help is appreciated, thanks in advance!
The general version for rotation and aspect ratio is:
(center_c, center_y) being the center of rotation
(aspect_x, aspect_y) being the aspect_ratio
tmp_x = (x-center_x)/aspect_x
tmp_y = (y-center_y)/aspect_y
tmp_x = tmp_x * cos(theta) - tmp_y * sin(theta)
tmp_x = tmp_x * sin(theta) + tmp_y * cos(theta)
new_x = aspect_x*tmp_x-center_x
new_y = aspect_y*tmp_x-center_y
Hope that helps.
I have three points, lets say C as a center point while P1 and P2 are two other points.
I have computed angle between C and P1 know as angle1 and c p2 called angle 2.
here is the code I use to compute it
angle1 = atan2(p1.y - c.y, p1.x - c.x);
angle2 = atan2(p2.y - c.y, p2.x - c.x);
after that I changed them into degrees by using this.
if (angle1 >= 0)
angle1 = angle1 * (180 / PI);
else
angle1 = (angle1 + 2 * PI) * (180 / PI);
if(angle2 >= 0)
angle2 = angle2 * (180 / PI);
else
angle2 = (angle2 + 2 * PI) * (180 / PI);
Then I use this openCv method to compute draw the arc, some time arc is perfect between two point while some times it fills all the circle other than the two points which I post image here.
radius = sqrt(pow(c.x - p1.x, 2.0) + pow(c.y - p1.y, 2.0));
ellipse(outPutMat, c, cv::Size(radius, radius), 0, angle1, angle2, Scalar(0, 0, 0), -1, 8, 0);
here are the images
red points are the points, while black is ellipse filled color.
For 1st image agngle1 = 42.1376 while angle2 = 338.962
For 2nd image agngle1 = 152.447 while angle2 = 223.363
2nd image produced right results but first is wrong. I just want to fill area between points.
After short check - it seems that OpenCV function calculates middle angle as ma = (angle1 + angle2) / 2 and draws arc through this point.
Both (-45,45) and (45,-45) give the same 90-degrees arc through zero, both (315,45) and (45,315) give the same 270-degrees arc.
To get desired result, you have not map negative angle to positive value ((angle1 + 2 * PI)), and use 42 and -21 values in the first case.