【问题标题】:Checking whether two rectangles overlap in python using two bottom left corners and top right corners使用两个左下角和右上角检查两个矩形是否在python中重叠
【发布时间】:2017-04-09 07:22:04
【问题描述】:
class Point:

    def __init__(self, xcoord=0, ycoord=0):
        self.x = xcoord
        self.y = ycoord

class Rectangle:
    def __init__(self, bottom_left, top_right, colour):
        self.bottom_left = bottom_left
        self.top_right = top_right
        self.colour = colour

    def intersects(self, other):

我正在尝试根据右上角和左下角查看两个矩形是否相交但是当我创建函数时:

def intersects(self, other):
    return self.top_right.x>=other.top_right.x>=self.bottom_left.x and self.top_right.x>=other.bottom_left.x>=self.bottom_left.x and self.top_right.y>=other.top_right.y>=self.bottom_left.y and self.top_right.x>=other.bottom_left.x>=self.bottom_left.x

输入时函数会返回false:

r1=Rectangle(Point(1,1), Point(2,2), 'blue')
r3=Rectangle(Point(1.5,0), Point(1.7,3), 'red')
r1.intersects(r3)

进入外壳。

【问题讨论】:

  • “我想看看两个三角形是否相交”——你的意思是“矩形”吗?
  • 如果您对一个矩形使用 4 个点,或者为每个矩形计算剩余的 2 个点,这将非常容易。然后,每当矩形 a 的一个点包含在矩形 b 中时,它们就会重叠。 ;)

标签: python python-3.x


【解决方案1】:

比较我找到的所有答案,@samgak answer 是最好的。

def is_overlapping_1D(line1, line2):
    """
    line:
        (xmin, xmax)
    """
    return line1[0] <= line2[1] and line2[0] <= line1[1]

def is_overlapping_2d(box1, box2):
    """
    box:
        (xmin, ymin, xmax, ymax)
    """
    return is_overlapping_1D([box1[0],box1[2]],[box2[0],box2[2]]) and is_overlapping_1D([box1[1],box1[3]],[box2[1],box2[3]])

from shapely.geometry import Polygon
def overlap2(box1, box2):
    p1 = Polygon([(box1[0],box1[1]), (box1[0],box1[3]), (box1[2],box1[3]),(box1[2],box1[1])])
    p2 = Polygon([(box2[0],box2[1]), (box2[0],box2[3]), (box2[2],box2[3]),(box2[2],box2[1])])
    return p1.intersects(p2)

def intersects(box1, box2):
    return not (box1[2] < box2[0] or box1[0] > box2[2] or box1[1] > box2[3] or box1[3] < box2[1])
# xyxy (xmin, xmax, ymin, ymax)
boxes = [
    (200,70,240,110),
    (10,10,60,60),
    (30,20,70,60),
    (100, 90, 190, 180),
    (50,100,150,200),
    (180,190,220,230),
    (10,210,40,240)
]
%%timeit
boxes_merged = iterate_merge(intersects, unify, boxes)

%%timeit
boxes_merged = iterate_merge(overlap2, unify, boxes)

%%timeit
boxes_merged = iterate_merge(is_overlapping_2d, unify, boxes)
67.5 µs ± 313 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

924 µs ± 1.12 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

83.1 µs ± 223 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

【讨论】:

    【解决方案2】:

    我最近遇到了这个问题,今天遇到了命名元组,所以我想我会试一试:

    from collections import namedtuple
    
    RECT_NAMEDTUPLE = namedtuple('RECT_NAMEDTUPLE', 'x1 x2 y1 y2')
    
    Rect1 = RECT_NAMEDTUPLE(10,100,40,80)
    Rect2 = RECT_NAMEDTUPLE(20,210,10,60)
    
    def overlap(rec1, rec2):
      if (rec2.x2 > rec1.x1 and rec2.x2 < rec1.x2) or \
         (rec2.x1 > rec1.x1 and rec2.x1 < rec1.x2):
        x_match = True
      else:
        x_match = False
      if (rec2.y2 > rec1.y1 and rec2.y2 < rec1.y2) or \
         (rec2.y1 > rec1.y1 and rec2.y1 < rec1.y2):
        y_match = True
      else:
        y_match = False
      if x_match and y_match:
        return True
      else:
        return False
    
    print ("Overlap found?", overlap(Rect1, Rect2))
    
    Overlap found? True
    
    

    【讨论】:

      【解决方案3】:

      也可以用 Polygon from shapely 来完成(例如带有 [x0,y0,x1,y1] 的矩形

      from shapely.geometry import Polygon
      import numpy as np
      
      rect1=np.array([0  ,0 ,3,  3])
      rect2=np.array([1, 1 , 4 , 4])
      
      def overlap2(rect1,rect2):
          p1 = Polygon([(rect1[0],rect1[1]), (rect1[1],rect1[1]),(rect1[2],rect1[3]),(rect1[2],rect1[1])])
          p2 = Polygon([(rect2[0],rect2[1]), (rect2[1],rect2[1]),(rect2[2],rect2[3]),(rect2[2],rect2[1])])
          return(p1.intersects(p2))
      
      print(overlap2(rect1,rect2))
      

      【讨论】:

      • 嘿嘿。 try / except 是否可以处理具有相等边界的矩形?
      • 不,我认为 try/except 是我较大的代码项目的多余部分 - 我删除了它以使解决方案更简单,谢谢
      • 由于编辑队列已满,这里更正:Polygon([(rect1[0],rect1[1]), (rect1[1],rect1[1]),(rect1[2],rect1[3]),(rect1[2],rect1[1]) to Polygon([(rect1[0],rect1[1]), (rect1[0],rect1[3]),(rect1[2],rect1[3]),(rect1[2],rect1[1])
      【解决方案4】:

      在编写代码之前,您可以执行以下操作: 1.想想两个矩形不会重叠的情况 2. 首先选择每个颜色编码的 x 和 y 的配对比较。 例如比较 rectangle.A.X1 并将其与 Rectangle.B.X2 进行比较

      这里是代码

      def check_for_overlap():
          rectangle_a  = {"x1":15, "y1":10, "x2":10,"y2":5}
          rectangle_b  = {"x1": 25, "y1":10, "x2":20,"y2":5}
          #black color                           or    red color
          if(rectangle_a["y1"]<rectangle_b["y2"] or rectangle_a["x1"]<rectangle_b["x2"]):
              print("no overlap ")
          #the blue color                          or   green 
          elif(rectangle_a["x2"]>rectangle_b["x1"] or rectangle_a["y2"]>rectangle_b["y1"]):
              print("no overlap ")
          else:
              print("YES ! there is a overlap")
      
      check_for_overlap()
      

      【讨论】:

        【解决方案5】:

        我所做的是找出哪个矩形在顶部,哪个在底部;哪个在左边,哪个在右边。最终,我们谈论的是我们正在比较的相同的两个矩形。但是获得右/左和上/下有助于简化条件。一旦我们得到了右/左和上/下,我们就可以比较重叠、非重叠和包含。

        class Rectangle:
        # Create rectangle with center at (x, y)
        # width x, and height h
        
            def __init__(self, x, y, w, h):
            self._x = float(x)
            self._y = float(y)
            self._width = float(w)
            self._height = float(h)
            # Extended four instance variables
            self._x0 = self._x - self._width / 2
            self._x1 = self._x + self._width / 2
            self._y0 = self._y - self._height / 2
            self._y1 = self._y + self._height/2
            # True if self intersects other; False otherwise
            def intersects(self, other):
        
                # find which rectangle is on the left
                leftRec = None
                rightRec = None
                if self._x1 >= other._x1:
                    leftRec = other
                    rightRec = self
                else:
                    leftRec = self
                    rightRec = other
        
                # find which rectangle is on the top
                topRec = None
                lowRec = None
                if self._y1 >= other._y1:
                    topRec = self
                    lowRec = other
                else:
                    topRec = other
                    lowRec = self
        
                if (leftRec._x0 + leftRec._width <= rightRec._x0) or (lowRec._y0 + lowRec._height <= topRec._y0):
                    # Not overlap
                    return False
                elif (leftRec._x0 + leftRec._width <= rightRec._x0 + rightRec._width) or (lowRec._y0 + lowRec._height <= topRec._y0 + topRec._height):
                    # full overlap, contains
                    return False
                else:
                    # intersect
                    return True
        

        基本上,如果左矩形的左下 x 值加上它的宽度小于右矩形的左下 x 值,则它是不重叠的。如果左矩形的左下 x 值加上它的宽度小于或等于右矩形的左下 x 值加上它的宽度,那么右边与左边完全重叠。除了这些以外,是交叉点。上下对比一下,再结合起来,就可以找到交点了。

        【讨论】:

          【解决方案6】:

          您可以使用Separating Axis Theorem 的简单版本来测试相交。如果矩形不相交,则至少一个右侧将位于另一个矩形左侧的左侧(即它将成为分离轴),反之亦然,或者顶侧之一将是低于另一个矩形的底边,反之亦然。

          因此更改测试以检查它们不相交是否不正确:

          def intersects(self, other):
              return not (self.top_right.x < other.bottom_left.x or self.bottom_left.x > other.top_right.x or self.top_right.y < other.bottom_left.y or self.bottom_left.y > other.top_right.y)
          

          此代码假定“顶部”的 y 值大于“底部”(y 在屏幕下方减小),因为您的示例似乎就是这样工作的。如果您使用的是其他约定,那么您只需翻转 y 比较的符号。

          【讨论】:

          • 有没有办法用多个矩形检查这个?
          • @prb 蛮力方法就是在每个矩形与所有其他矩形之间进行成对检查。为了提高效率,请将矩形存储在空间数据结构(例如四叉树)中,并使用它来生成要比较的候选对列表。适合您的数据结构的确切类型取决于您的数据(例如,矩形是否都具有相似的大小、密集排列或稀疏分布等)
          • 愚蠢的问题,但在这个解决方案中,你的 x 轴从最左边开始,对吗/
          • 使用 self 作为 python 变量名不会混淆吗?
          • @prb 我认为您应该为此提出单独的问题。我设法以低效的方式解决了多个矩形,但有效。
          猜你喜欢
          • 1970-01-01
          • 2017-05-13
          • 2021-08-21
          • 1970-01-01
          • 2018-09-29
          • 2018-08-28
          • 2011-07-06
          • 1970-01-01
          相关资源
          最近更新 更多