HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonModerate

Overlapping rectangles

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
overlappingrectanglesstackoverflow

Problem

I received the following question in a technical interview today (for a devops/SRE position):


Write a function which returns true if the two rectangles passed to it
as arguments would overlap if drawn on a Cartesian plane. The
rectangles are guaranteed to be aligned with the axes, not arbitrarily
rotated.

I pretty much blew the whole thought process for how to approach the question I wasn't thinking of cases where, for example, one rectangle might be enclosed entirely within the other or of cases where a short wide rectangle might cross wholly through a taller, narrower one forming some sort of cross --- so I was off on a non-productive tangent thinking about whether any corner of either rectangle was within the bounding box of the other.

Naturally as soon as I got home, having let the problem settle more in my mind, I was able to write something which seems reasonably elegant and seems to work (for the test cases I've tried so far).

This graphic (which took far longer to create than the code, and I don't even know how to make Inkscape show the gridlines in the saved image as it's showing in my working canvas) shows the simplest obvious cases: red/aqua overlapping by a corner, blue completely enclosing fuschia and green/yellow overlapping but without any corner enclosed within the other. My test code uses red/blue, blue/green and similar combinations as the non-overlapping test cases, including those which would overlap only in horizontal or vertical dimensions but are clear in the other dimension.

My thought process, when I got home and sat down with a keyboard was as follows:

We only care about edges, ultimately. So my Rect() class store just the X scalar of the left and right edges, and the Y scalar of top and bottom edges.

For rectangles to overlap there must be some overlap in both the horizontal and vertical directions. So it should be sufficient to just test if either the left or right edge of the first rectangle argument is to the right

Solution

You have common code, which moreover has applications beyond this one, so should you not pull it out into a function? Then you can reduce overlap to

def overlap(r1, r2):
'''Overlapping rectangles overlap both horizontally & vertically
'''
return range_overlap(r1.left, r1.right, r2.left, r2.right) and range_overlap(r1.bottom, r1.top, r2.bottom, r2.top)


Now, the key condition encapsulated by range_overlap is that neither range is completely greater than the other. A direct refactor of the way you've expressed this is

def range_overlap(a_min, a_max, b_min, b_max):
'''Neither range is completely greater than the other
'''
overlapping = True
if (a_min > b_max) or (a_max

For such a simple condition I would prefer to use
not rather than if-else assignment. I would also reorder the second condition to exhibit the symmetry more clearly:

def range_overlap(a_min, a_max, b_min, b_max):
    '''Neither range is completely greater than the other
    '''
    return not ((a_min > b_max) or (b_min > a_max))


Of course, de Morgan's laws allow rewriting as

def range_overlap(a_min, a_max, b_min, b_max):
    '''Neither range is completely greater than the other
    '''
    return (a_min <= b_max) and (b_min <= a_max)


I think that the last of these is the most transparent, but that's an issue of aesthetics and you may disagree.

Note that I've assumed throughout, as you do, that the rectangles are closed (i.e. that they contain their edges). To make them open, change
> to >= and <= to <`.

Code Snippets

def range_overlap(a_min, a_max, b_min, b_max):
    '''Neither range is completely greater than the other
    '''
    return not ((a_min > b_max) or (b_min > a_max))
def range_overlap(a_min, a_max, b_min, b_max):
    '''Neither range is completely greater than the other
    '''
    return (a_min <= b_max) and (b_min <= a_max)

Context

StackExchange Code Review Q#31352, answer score: 18

Revisions (0)

No revisions yet.