【问题标题】:How do I get the rectangles which would fill out a space *excluding* some other rectangles?如何获得填充空间的矩形*不包括*其他一些矩形?
【发布时间】:2020-03-03 14:19:58
【问题描述】:

标题说明了一切。例如: 给定红色矩形,我想获得所有绿色矩形。 我知道边界矩形的大小。

红色矩形可能重叠。

【问题讨论】:

  • @xerx593 我正在尝试计算 A-G。我只有红色矩形。
  • 不知道边界框的大小吗?
  • @GilbertLeBlanc 好吧,我知道。已编辑。
  • 我不能画图,但是是什么阻止了矩形 E 一直延伸到边界框的顶部?
  • 有多种构建 A-G 矩形的方法,您对此有限制吗?例如,您是否需要获得最少数量的矩形,或者不一定?然后,任何具有正确数量的矩形的配置?

标签: algorithm rectangles


【解决方案1】:

这是一个分而治之的算法;这个想法与quicksort 大体相似。我假设矩形不重叠,并且它们都包含在边界框中,尽管边界可能会接触。

  • 如果边界框退化(即零宽度或零高度),则什么也不做。
  • 否则,如果没有矩形,则只生成边界框本身。
  • 否则:
    • 从列表中选择一个矩形作为“轴”。
    • 为枢轴“上方”、“左”、“右”和“下方”创建新的边界框。
    • 通过过滤与每个新边界框相交的矩形列表,并将它们剪切到边界框,构建枢轴“上方”、“左侧”、“右侧”和“下方”的矩形列表。
    • 用新的矩形列表分别递归地细分“上方”、“左侧”、“右侧”和“下方”边界框。

每个矩形最多可以参与 4 次递归调用中的 2 次。如果枢轴是随机选择的,并且大多数矩形不与大多数其他矩形垂直重叠,那么平均每个矩形都参与一个递归调用。由于非递归工作需要线性时间,因此这种情况下的预期运行时间为 O(n log n),其中 n 是矩形的数量。

Python 中的实现:

import random
from collections import namedtuple

Rectangle = namedtuple('Rectangle', 'x1 y1 x2 y2')

def intersects(b, r):
    return b.x1 < r.x2 and b.x2 > r.x1 and b.y1 < r.y2 and b.y2 > r.y1

def clip_rect(b, r):
    return Rectangle(
        max(b.x1, r.x1), max(b.y1, r.y1),
        min(b.x2, r.x2), min(b.y2, r.y2)
    )

def clip_rects(b, rects):
    return [clip_rect(b, r) for r in rects if intersects(b, r)]

def split_rectangles(b, rects):
    if b.x1 >= b.x2 or b.y1 >= b.y2:
        pass
    elif not rects:
        yield b
    else:
        # randomize to avoid O(n^2) runtime in typical cases
        # change this if deterministic behaviour is required
        pivot = random.choice(rects)

        above = Rectangle(b.x1,     b.y1,     b.x2,     pivot.y1)
        left  = Rectangle(b.x1,     pivot.y1, pivot.x1, pivot.y2)
        right = Rectangle(pivot.x2, pivot.y1, b.x2,     pivot.y2)
        below = Rectangle(b.x1,     pivot.y2, b.x2,     b.y2)

        yield from split_rectangles(above, clip_rects(above, rects))
        yield from split_rectangles(left,  clip_rects(left,  rects))
        yield from split_rectangles(right, clip_rects(right, rects))
        yield from split_rectangles(below, clip_rects(below, rects))

示例:如您所见,它没有使用最少数量的矩形,因为右侧有两个可以垂直连接在一起。

如果最小化矩形的数量很重要,您可能需要考虑“上方”、“左侧”、“右侧”和“下方”的不同边界框,并再次检查结果以将所有矩形连接在一起如果它们有两条边相等的线段。

【讨论】:

    【解决方案2】:

    最简单的解决方案如下。

    创建两个列表xlistylist,对于每个红色矩形及其每个角,将该点的x 坐标插入xlist,并将y 坐标插入ylist。对边界框执行相同操作。

    xlistylist 中的重复项进行排序和删除。

    对于xlist中的每两个相邻元素x1x2ylist中的每两个相邻元素y1y2(两个嵌套的for循环),使用坐标x1x2y1y2(除非新的绿色矩形与任何红色矩形重叠)。

    这会给你更多的绿色矩形,但你没有给出任何限制,所以就这样;)

    如果您想限制矩形的数量,您可以轻松地将相邻的绿色矩形合并到一行中。

    【讨论】:

    • 好吧,所以我添加了一个 third for 循环(或者,可能为红色矩形使用一个集合)检查 x1、y1、x2、y2 是否等于红色矩形?
    • 实际上它们确实重叠。抱歉,我忘记在问题中添加这些内容。
    • @FireCubez 完全正确。为简单起见,您可以使用红色矩形的哈希图。只需注意编写正确的比较/等于和哈希码方法
    【解决方案3】:

    一种解决方案,为您提供绿色矩形的一种可能性,不一定与图片中的相同,也不一定是矩形数量最少的一个:

    • 获取位于红色矩形开头或结尾的所有ys 的排序列表。
    • 在列表的开头添加 0,在列表的末尾添加总高度。
    • 对于每个 (y1, y2) 间隔:
      • 检查哪些红色矩形在y1y2之间的水平带中,按x坐标排序
      • 创建左坐标和右坐标的排序列表:left_list[i] 将包含第 i 个矩形的左边界(类似于right_list)。添加 0 作为right_list 的第一个元素,总宽度作为left_list 的最后一个元素
      • 对于所有 i,在 x 上的 right_list[i]left_list[i] 之间以及在 y 上的 y1y2 之间创建一个绿色矩形。

    【讨论】:

    • “在 right_i 和 left_i+1 之间创建一个绿色矩形”是什么?
    【解决方案4】:

    从图中可以看出,矩形 A 填满了红色矩形 1 上方的所有空间。

    矩形 B 填充红色矩形 1 左侧的所有空间。

    矩形 C 填充了红色矩形 1 右侧的所有空间。

    矩形 D 被两个红色矩形包围。

    矩形 E - G 填充剩余空间(上、右、下)。

    算法似乎是,取每个红色矩形并填充它周围的空间。除非有其他限制,否则似乎就是这个过程。

    【讨论】:

      猜你喜欢
      • 2023-03-06
      • 1970-01-01
      • 1970-01-01
      • 2019-03-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多