The bounding box of a rotated object

(4 comments)

The following code plots a two-dimensional object and its bounding box for several rotations about an arbitrary point. Three types of bounding box are considered: (1) the original bounding box, rotated by the same amount as the object, (2) the bounding box to that bounding box (such that its sides remain parallel to the axes), and (3) the bounding box to the rotated object with sides parallel to the axes).

enter image description here

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Circle
DPI = 72

# Rotation centre. It is helpful to have this with shape (2,1)
cx, cy = 150, 50
rc = np.array(((cx, cy),)).T

# Initial width and height of the bounding rectangle we will fit the object in.
rw, rh = 200, 300
# Initial corner positions of the bounding rectangle 
x1, y1, x2, y2 = 250, 50, 250+rw, 50+rh

def rotate_points(pts, theta, rc):
    """Rotate the (x,y) points pts by angle theta about centre rc."""
    c, s = np.cos(theta), np.sin(theta)
    R = np.array(((c,-s), (s, c)))
    return rc + R @ (pts - rc)


def plot_poly(pts, colour='tab:blue', lw=2, opacity=1, ls='-'):
    """Plot a closed polygon with vertices at pts."""

    plot_pts = np.vstack((pts.T, pts[:,0]))
    ax.plot(*zip(*plot_pts), c=colour, lw=lw, alpha=opacity, ls=ls)


def plot_obj(pts, colour='tab:green', lw=2):
    """Draw the object we are rotating: a circle and polygon."""

    plot_poly(pts[:,1:], colour, lw=lw, opacity=0.5)
    circle = Circle(pts[:,0], obj_cr, edgecolor=colour, fill=False, lw=lw,
                    alpha=0.5)
    ax.add_patch(circle)


def get_boundary_pts(pts):
    """Get the vertices of the bounding rectangle for the points pts."""

    xmin, xmax = np.min(pts[0]), np.max(pts[0])
    ymin, ymax = np.min(pts[1]), np.max(pts[1])
    return np.array(((xmin,ymin), (xmax,ymin), (xmax, ymax), (xmin, ymax))).T


def get_obj_boundary(obj_pts):
    """Get the vertices of the bounding rectangle for the rotated object."""

    fcx, fcy = obj_pts[:,0]
    # Get the boundary from the triangle coordinates and the circle limits
    _obj_boundary = np.vstack((obj_pts.T[1:], (fcx-obj_cr, fcy),
                (fcx+obj_cr, fcy), (fcx, fcy-obj_cr), (fcx, fcy+obj_cr))).T
    return get_boundary_pts(_obj_boundary)


fig, ax = plt.subplots(figsize=(8.33333333, 8.33333333), dpi=DPI)

# Initial bounding rectangle of unrotated object.
pts = np.array( ((x1,y1), (x2,y1), (x2,y2), (x1,y2)) ).T
# The radius of the circle in our plotted object.
obj_cr = (rh - rw*np.sqrt(3)/2)/2
# The coordinates defining our object.
obj_pts = np.array( ((x1 + rw/2, y1 + rh - obj_cr),    # circle centre
                     (x1, y1), (x2, y1),               #
                     (x1+rw/2, y2-2*obj_cr),           # triangle
                    )).T
# Plot the unrotated object and its bounding rectangle
plot_obj(obj_pts)
plot_poly(pts)

nrots = 60
theta = np.radians(360 // nrots)
boundary_trail_pts, obj_boundary_trail_pts = [], []
for i in range(nrots):
    fig, ax = plt.subplots(figsize=(8.33333333, 6.25), dpi=DPI)
    ax.set_xlim(-600,600)
    ax.set_ylim(-600,600)
    # Indicate the centre of rotation
    ax.add_patch(Circle((cx,cy), 10))

    # Plot the object
    plot_obj(obj_pts)
    # Plot the rotated object's boundary
    boundary_pts = get_obj_boundary(obj_pts)
    plot_poly(boundary_pts, colour='tab:purple', ls='--')
    obj_boundary_trail_pts.append(np.mean(boundary_pts, axis=1))
    ax.plot(*zip(*obj_boundary_trail_pts), c='tab:purple', ls='--')

    # Plot the original boundary, rotated
    plot_poly(pts, colour='tab:orange')
    # Plot the boundary to the original rotated boundary
    boundary_pts = get_boundary_pts(pts)
    plot_poly(boundary_pts, colour='tab:orange', ls=':')
    boundary_trail_pts.append(np.mean(boundary_pts, axis=1))
    ax.plot(*zip(*boundary_trail_pts), c='tab:orange', ls=':')

    plt.savefig('frames/bbrot-{:03d}.png'.format(i+1), dpi=DPI)

    obj_pts = rotate_points(obj_pts, theta, rc)
    pts = rotate_points(pts, theta, rc)
    plt.close(fig)
Current rating: 5

Comments

Comments are pre-moderated. Please be patient and your comment will appear soon.

Pooja Kashikar 4 years, 3 months ago

not working.

Link | Reply
Current rating: 2.1

christian 4 years, 3 months ago

Sorry to hear that, Pooja. Can you be a little more specific about what the problem (error message, etc.) is?

Link | Reply
Current rating: 4.3

Vijay Gill 4 years, 3 months ago

The code works. I have tested it myself. Most likely your environment is not set up. Missing packages? Or did you create the folder "frames" in the folder where you placed this script?

Link | Reply
Current rating: 1

Vijay Gill 4 years, 3 months ago

It works. Added to my bookmarks now. Thanks for your code.

Link | Reply
Current rating: 1

New Comment

required

required (not published)

optional

required