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)
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. $$
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?