Intersection and difference of two rectangles

前端 未结 3 1027
梦如初夏
梦如初夏 2020-12-06 14:49

Searching the internet has not given a satisfactory solution for the following problem. Given a class Rectangle defined as the following:

class          


        
3条回答
  •  误落风尘
    2020-12-06 15:36

    Here is a complete solution for you.
    Methods in the class are ordered illogically so that the important parts are visible without scrolling.

    import itertools
    
    class Rectangle:
        def intersection(self, other):
            a, b = self, other
            x1 = max(min(a.x1, a.x2), min(b.x1, b.x2))
            y1 = max(min(a.y1, a.y2), min(b.y1, b.y2))
            x2 = min(max(a.x1, a.x2), max(b.x1, b.x2))
            y2 = min(max(a.y1, a.y2), max(b.y1, b.y2))
            if x1x2 or y1>y2:
                raise ValueError("Coordinates are invalid")
            self.x1, self.y1, self.x2, self.y2 = x1, y1, x2, y2
    
        def __iter__(self):
            yield self.x1
            yield self.y1
            yield self.x2
            yield self.y2
    
        def __eq__(self, other):
            return isinstance(other, Rectangle) and tuple(self)==tuple(other)
        def __ne__(self, other):
            return not (self==other)
    
        def __repr__(self):
            return type(self).__name__+repr(tuple(self))
    
    
    def pairwise(iterable):
        # https://docs.python.org/dev/library/itertools.html#recipes
        a, b = itertools.tee(iterable)
        next(b, None)
        return zip(a, b)
    
    
    # 1.
    a = Rectangle(0, 0, 1, 1)
    b = Rectangle(0.5, 0.5, 1.5, 1.5)
    print(a&b)
    # Rectangle(0.5, 0.5, 1, 1)
    print(list(a-b))
    # [Rectangle(0, 0, 0.5, 0.5), Rectangle(0, 0.5, 0.5, 1), Rectangle(0.5, 0, 1, 0.5)]
    
    # 2.
    b = Rectangle(0.25, 0.25, 1.25, 0.75)
    print(a&b)
    # Rectangle(0.25, 0.25, 1, 0.75)
    print(list(a-b))
    # [Rectangle(0, 0, 0.25, 0.25), Rectangle(0, 0.25, 0.25, 0.75), Rectangle(0, 0.75, 0.25, 1), Rectangle(0.25, 0, 1, 0.25), Rectangle(0.25, 0.75, 1, 1)]
    
    # 3.
    b = Rectangle(0.25, 0.25, 0.75, 0.75)
    print(a&b)
    # Rectangle(0.25, 0.25, 0.75, 0.75)
    print(list(a-b))
    # [Rectangle(0, 0, 0.25, 0.25), Rectangle(0, 0.25, 0.25, 0.75), Rectangle(0, 0.75, 0.25, 1), Rectangle(0.25, 0, 0.75, 0.25), Rectangle(0.25, 0.75, 0.75, 1), Rectangle(0.75, 0, 1, 0.25), Rectangle(0.75, 0.25, 1, 0.75), Rectangle(0.75, 0.75, 1, 1)]
    
    # 4.
    b = Rectangle(5, 5, 10, 10)
    print(a&b)
    # None
    print(list(a-b))
    # [Rectangle(0, 0, 1, 1)]
    
    # 5.
    b = Rectangle(-5, -5, 10, 10)
    print(a&b)
    # Rectangle(0, 0, 1, 1)
    print(list(a-b))
    # []
    

    Intersection is based on SFML's implementation. It is proven correct and is not interesting to explain.

    The difference, however, was a lot of fun to make.

    Consider the following cases and compare them with corresponding examples at the bottom of the code. The method may return from 0 to 8 rectangles!

    Rectangle intersection cases

    It works by finding all the vertical (xs) and horizontal (ys) lines that go through our rectangle (all the black and grey lines on the picture).

    The coordinate sets are turned into sorted lists and taken pairwise ([a, b, c] becomes [(a, b), (b, c)]).

    The product of such horizontal and vertical segments gives us all the rectangles that we divided the original one into by these lines.

    All that remains is to yield all of these rectangles except the intersection.

提交回复
热议问题