Calculate maximum rotation of rectangle inside rectangle

euclidean-geometrygeometrytrigonometry

I've got two rectangles ABCD and EFHJ as shown in the example below.

I know the dimensions of the smaller and bigger rectangle and the vector between their centers KI.

How can I calculate the maximum angle at that I can rotate the inner rectangle so it would not protrude beyond the outer one.

The center point of rotation is center of the smaller rectangle.

Solution in python

inner_width, inner_height = 70, 100
outer_width, outer_height = 84, 130

offset_x = 0
offset_y = 10

inner_diagonal = sqrt(inner_width ** 2 + inner_height ** 2) / 2 

a = np.arctan(inner_height / inner_width)


half_height = outer_height / 2
distance_top = half_height + offset_y
distance_bottom = half_height - offset_y

half_width = outer_width / 2
distance_left = half_width + offset_x 
distance_right = half_width - offset_x

c = 0
if inner_diagonal > distance_bottom:
    c = max(c, np.arccos(distance_bottom / inner_diagonal))
if inner_diagonal > distance_top:
    c = max(c, np.arccos(distance_top / inner_diagonal))
if inner_diagonal > distance_left:
    c = max(c, np.arccos(distance_left / inner_diagonal))
if inner_diagonal > distance_right:
    c = max(c, np.arccos(distance_right / inner_diagonal))

angle = (pi / 2) - a - c 

Visualization

base = np.zeros((300, 300, 3), dtype="uint8")
width, height = base.shape[:2]
center_x, center_y = width / 2, height / 2


ox, oy = center_x + offset_x, center_y + offset_y
inner_points = [
    (int(ox - inner_width / 2), int(oy - inner_height / 2)),
    (int(ox + inner_width / 2), int(oy + inner_height / 2)),
    
    (int(ox - inner_width  / 2), int(oy + inner_height / 2)),
    (int(ox + inner_width  / 2), int(oy - inner_height / 2)),

]


for pt in inner_points:
    px, py = pt
    qx = ox + cos(angle) * (px - ox) - sin(angle) * (py - oy)
    qy = oy + sin(angle) * (px - ox) + cos(angle) * (py - oy)
    base = cv2.circle(base, (int(qx), int(qy)), 3, (255, 255, 255))
    
    qx = ox + cos(-angle) * (px - ox) - sin(-angle) * (py - oy)
    qy = oy + sin(-angle) * (px - ox) + cos(-angle) * (py - oy)
    base = cv2.circle(base, (int(qx), int(qy)), 3, (255, 0, 0))


base = cv2.rectangle(
    base,
    *inner_points[:2],
    (255, 255, 255),
)

base = cv2.rectangle(
    base,
    (int(center_x - outer_width / 2), int(center_y - outer_height / 2)),
    (int(center_x + outer_width / 2), int(center_y + outer_height / 2)),
    (255, 255, 255),
)


Image.fromarray(base)

enter image description here

Best Answer

In this picture, $$ a = \arctan MF/ML $$ and since $LF = LF'$, $$ c = \arccos LF"/LF $$ so the counterclockwise rotation angle is $$ b = \pi/2 - a - c. $$ enter image description here

You can do the same kind of calculation for the other corners of the small rectangle and find the smallest $b$.

In code you will have several cases to manage. Can the small rectangle be so small that it rotates all the way around?

Related Question