Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calculating point and dimensions of maximum rotated rectangle inside rectangle

I have a rectangle that has to be rotated always the same amount of degrees. Lets call this angle alpha (𝜶).

The width (w) and height (h) of this rectangle can vary. The rectangle has always to fit rotated inside the big rectangle. It must be scaled up or down to fit inside the gray rectangle.

NOTE: Alpha is the angle between w and the horizontal line.

So, there are 3 kinds of rectangles where

w > h
w < h  or
w = h

See the picture below.

enter image description here

What I know:

  1. The big rectangle has width of R and height of K and I know both values;
  2. w and h are unknown;
  3. the rectangle is always rotated 𝜶 degrees;
  4. I know the value of w/h. I call this "ratioWH";
  5. red rectangle is always centered horizontally and vertically on the gray rectangle

what I need to know:

  1. the maximum values of w and h that will fit the gray rectangle for each case of w and h.
  2. the coordinates of point P, assuming that 0,0 is at the upper left of the gray rectangle.

This is what I did so far, but this is not giving the correct values:

CGPoint P = CGPointZero;

if (ratioWH > 0) { // means w > h

    maxH = R / (ratioWH * fabsf(cosf(theta)) + fabsf(sinf(theta)));
    maxW = maxH * ratioWH;

    // P.x = 0.0f;  // P.x is already zero
    CGFloat marginY = (K - maxW * fabsf(sinf(theta)) - maxH * fabsf(cosf(theta))) / 2.0f;
    P.y = marginY +  maxW * fabsf(sinf(theta));

} else { // w <= h

    maxW  = K / (fabsf(cosf(theta) / ratioImagemXY) + fabsf(sinf(theta)));
    maxH = maxW / ratioWH;


    P.x = (R - maxW * fabsf(cosf(theta)) - maxH * fabsf(sinf(theta))) / 2.0f;
    P.y = maxW * fabsf(sinf(theta));

} 

any clues? Thanks.

like image 779
Duck Avatar asked Oct 29 '12 20:10

Duck


People also ask

How do you find the points of rotation of a rectangle?

The essence is this: (1) If c is the center point, then the corners are c + (L/2,W/2), +/- etc., where L and W are the length & width of the rectangle. (2) Translate the rectangle so that center c is at the origin, by subtracting c from all four corners. (3) Rotate the rectangle by 40 deg via the trig formulas cited.


1 Answers

The way I see it is like this... You work out the total width and total height of the rectangle. For that, you simply walk along two edges. Like this:

dx = w * cos(theta) + h * sin(theta)
dy = h * cos(theta) + w * sin(theta)

These could be negative, so special handling would apply if the rectangle is rotated into other quadrants. This will happen later.

You now just need the ratio between the width and height. This is where you decide whether to scale by the vertical amount or the horizontal amount. It's nothing to do with w and h -- it's actually about where the rectangle ends up as a result of rotation. That's what dx and dy are for.

rectratio = abs( dx / dy )
viewratio = R / K

If rectratio comes out larger than viewratio that means the rotated rectangle's horizontal footprint needs to be scaled. Otherwise you scale by the vertical footprint.

if rectratio > viewratio
    scale = R / abs(dx)
else
    scale = K / abs(dy)
end

And the scale itself is applied to the original width and height

sw = scale * w
sh = scale * h

So now you can compute the corners of your rectangle. It doesn't matter where you start.

x[0] = 0
x[1] = x[0] + sw * cos(theta)
x[2] = x[1] + sh * sin(theta)
x[3] = x[2] - sw * cos(theta)

y[0] = 0
y[1] = y[0] - sw * sin(theta)
y[2] = y[1] + sh * cos(theta)
y[3] = y[2] + sw * sin(theta)

I've assumed image co-ordinates given that (0,0) is top-left, so increasing y moves down. So, if I haven't made a mistake in my math, the above gives you the rectangle vertices (in clockwise order).

The last thing to do is normalise them... This means finding the min value of px and py. Call them pxmin and pymin. I don't need to show code for that. The idea is to calculate an offset for your rectangle such that the view area is defined by the rectangle (0,0) to (R,K).

First we need to find the left and right value of the subview that completely contains our rotated rectangle... Remember the ratio before:

if( rectratio > viewratio )
    // view is too tall, so centre vertically:
    left = 0
    top = (K - scale * abs(dy)) / 2.0
else
    // view is too wide, so centre horizontally:
    left = (R - scale * abs(dx)) / 2.0
    top = 0
end

left and top are now the 'minimum' co-ordinate of our subview that exactly contains the rectangle (floating point rounding errors exempted). So:

left += pxmin
top += pymin

Now they are the offset required to shift the rectangle to where it's wanted. All you do is add left and top to all your rectangle co-ordinates, and you are done. The position of P is px[0] and py[0]. If you rotated by 90 degrees or more, it won't be the top-left vertex.

like image 98
paddy Avatar answered Sep 29 '22 04:09

paddy