【问题标题】:How do I check if a rectangle can fit into a bounding area?如何检查矩形是否适合边界区域?
【发布时间】:2022-06-10 20:29:34
【问题描述】:

我写了一个函数,可以生成很多这样的东西:

[
        (0, 619.5312394955338, 337.573529597446, 1080),
        (619.5312394955338, 1544.7619727875272, 0, 310.3079296654736),
        (619.5312394955338, 1544.7619727875272, 310.3079296654736, 337.573529597446),
        (1544.7619727875272, 1920, 0, 310.3079296654736),
        (619.5312394955338, 1088.2418093689296, 708.2009619111413, 1080),
        (1088.2418093689296, 1920, 337.573529597446, 708.2009619111413),
        (1088.2418093689296, 1920, 708.2009619111413, 1080),
        (0, 173.32617646340788, 288.56747000927186, 337.573529597446),
        (173.32617646340788, 619.5312394955338, 0, 288.56747000927186),
        (173.32617646340788, 619.5312394955338, 288.56747000927186, 337.573529597446),
        (0, 25.117144604340456, 177.08675820480235, 288.56747000927186),
        (25.117144604340456, 173.32617646340788, 0, 177.08675820480235),
        (25.117144604340456, 173.32617646340788, 177.08675820480235, 288.56747000927186),
        (0, 22.953859822450067, 0, 96.22494617847441),
        (0, 22.953859822450067, 96.22494617847441, 177.08675820480235),
        (22.953859822450067, 25.117144604340456, 0, 96.22494617847441),
        (22.953859822450067, 25.117144604340456, 96.22494617847441, 177.08675820480235),
        (619.5312394955338, 1061.0668595171933, 337.573529597446, 487.04072151109654),
        (619.5312394955338, 1061.0668595171933, 487.04072151109654, 708.2009619111413),
        (1061.0668595171933, 1088.2418093689296, 337.573529597446, 487.04072151109654),
        (1061.0668595171933, 1088.2418093689296, 487.04072151109654, 708.2009619111413),
        (1544.7619727875272, 1797.260895403902, 310.3079296654736, 324.5737372982961),
        (1544.7619727875272, 1797.260895403902, 324.5737372982961, 337.573529597446),
        (1797.260895403902, 1920, 310.3079296654736, 324.5737372982961),
        (1797.260895403902, 1920, 324.5737372982961, 337.573529597446)
]

第一个数字总是小于第二个数字,第三个数字总是小于第四个数字,前两个数字代表x坐标,后两个数字代表y坐标。

上面的列表代表了这个:

[
        [(0, 337.573529597446), (619.5312394955338, 337.573529597446), (619.5312394955338, 1080), (0, 1080)],
        [(619.5312394955338, 0), (1544.7619727875272, 0), (1544.7619727875272, 310.3079296654736), (619.5312394955338, 310.3079296654736)],
        [(619.5312394955338, 310.3079296654736), (1544.7619727875272, 310.3079296654736), (1544.7619727875272, 337.573529597446), (619.5312394955338, 337.573529597446)],
        [(1544.7619727875272, 0), (1920, 0), (1920, 310.3079296654736), (1544.7619727875272, 310.3079296654736)],
        [(619.5312394955338, 708.2009619111413), (1088.2418093689296, 708.2009619111413), (1088.2418093689296, 1080), (619.5312394955338, 1080)],
        [(1088.2418093689296, 337.573529597446), (1920, 337.573529597446), (1920, 708.2009619111413), (1088.2418093689296, 708.2009619111413)],
        [(1088.2418093689296, 708.2009619111413), (1920, 708.2009619111413), (1920, 1080), (1088.2418093689296, 1080)],
        [(0, 288.56747000927186), (173.32617646340788, 288.56747000927186), (173.32617646340788, 337.573529597446), (0, 337.573529597446)],
        [(173.32617646340788, 0), (619.5312394955338, 0), (619.5312394955338, 288.56747000927186), (173.32617646340788, 288.56747000927186)],
        [(173.32617646340788, 288.56747000927186), (619.5312394955338, 288.56747000927186), (619.5312394955338, 337.573529597446), (173.32617646340788, 337.573529597446)],
        [(0, 177.08675820480235), (25.117144604340456, 177.08675820480235), (25.117144604340456, 288.56747000927186), (0, 288.56747000927186)],
        [(25.117144604340456, 0), (173.32617646340788, 0), (173.32617646340788, 177.08675820480235), (25.117144604340456, 177.08675820480235)],
        [(25.117144604340456, 177.08675820480235), (173.32617646340788, 177.08675820480235), (173.32617646340788, 288.56747000927186), (25.117144604340456, 288.56747000927186)],
        [(0, 0), (22.953859822450067, 0), (22.953859822450067, 96.22494617847441), (0, 96.22494617847441)],
        [(0, 96.22494617847441), (22.953859822450067, 96.22494617847441), (22.953859822450067, 177.08675820480235), (0, 177.08675820480235)],
        [(22.953859822450067, 0), (25.117144604340456, 0), (25.117144604340456, 96.22494617847441), (22.953859822450067, 96.22494617847441)],
        [(22.953859822450067, 96.22494617847441), (25.117144604340456, 96.22494617847441), (25.117144604340456, 177.08675820480235), (22.953859822450067, 177.08675820480235)],
        [(619.5312394955338, 337.573529597446), (1061.0668595171933, 337.573529597446), (1061.0668595171933, 487.04072151109654), (619.5312394955338, 487.04072151109654)],
        [(619.5312394955338, 487.04072151109654), (1061.0668595171933, 487.04072151109654), (1061.0668595171933, 708.2009619111413), (619.5312394955338, 708.2009619111413)],
        [(1061.0668595171933, 337.573529597446), (1088.2418093689296, 337.573529597446), (1088.2418093689296, 487.04072151109654), (1061.0668595171933, 487.04072151109654)],
        [(1061.0668595171933, 487.04072151109654), (1088.2418093689296, 487.04072151109654), (1088.2418093689296, 708.2009619111413), (1061.0668595171933, 708.2009619111413)],
        [(1544.7619727875272, 310.3079296654736), (1797.260895403902, 310.3079296654736), (1797.260895403902, 324.5737372982961), (1544.7619727875272, 324.5737372982961)],
        [(1544.7619727875272, 324.5737372982961), (1797.260895403902, 324.5737372982961), (1797.260895403902, 337.573529597446), (1544.7619727875272, 337.573529597446)],
        [(1797.260895403902, 310.3079296654736), (1920, 310.3079296654736), (1920, 324.5737372982961), (1797.260895403902, 324.5737372982961)],
        [(1797.260895403902, 324.5737372982961), (1920, 324.5737372982961), (1920, 337.573529597446), (1797.260895403902, 337.573529597446)]
]

非重叠矩形的顶点坐标列表:

我想知道,给定一个宽度为w 和高度为h 的矩形,我如何有效地找到该矩形可以放入的所有边界框?

我只知道如何使用列表理解来做到这一点:

[(x1, x2, y1, y2) for x1, x2, y1, y2 in limits if x2 - x1 >= w and y2 - y1 >= h]

不允许旋转。并且位置被忽略。只有大小很重要。

【问题讨论】:

  • 只是为了确认,您只想知道矩形可以放入哪些边界框,而不管位置或方向如何? (即是否允许/需要轮换?)

标签: python python-3.x algorithm


【解决方案1】:

恕我直言,这是bin packing problem 的一个实例。 rectangle packing 的子类型。简而言之,这意味着,一般来说,没有比真正尝试所有可能的组合来找到匹配项更好/更快的解决方案了。

维基百科链接了两种不同的可能方法,并稍微改进了运行时间([1][2])。第一个旨在始终找到最佳解决方案,第二个也可以提出“好,但不完美”的解决方案。它们都很复杂,所以我不会在这里详细介绍。你可以看看它们,它们解释得很好,如果你感兴趣的话。

我个人的方法(没有那么详细)会更具启发性,但仍能找到最佳解决方案。启发式方法意味着,一些组合可以在过程中提前或很早就被消除,因此总体上执行的操作更少。

  • 对于每个给定的矩形,通过乘以宽度和高度来计算其面积。
  • 将这些值与矩形定义一起存储在支持按此区域值排序的数据结构中(如树形图)。
  • 对于每个用于比较的矩形,您可以忽略所有面积小于其自身面积的给定矩形。因此,您只需剪掉一些源矩形进行比较。
  • 无论如何,对于剩余的每个源矩形,您仍然需要进行宽度和高度的填充比较。

我没有根据所需的(更少)操作来计算我的解决方案的性能增益,当然,就像每个启发式方法一样,它高度依赖于您必须处理的具体矩形实例。但总的来说,尽管初始开销较大(用于计算所有区域),但您应该更快一点,因为 - 平均而言 - 您对每个矩形进行的比较较少。

【讨论】:

    【解决方案2】:

    如果你有很多矩形和很多测试要做,那么你可以用partially persistent红黑树或类似的东西来解决这个问题。部分持久性意味着所有以前版本的数据结构在您更改后仍然可以访问。

    此解决方案将需要 O(N log N) 时间和空间来设置数据结构,但随后只需 O(log N + output_size) 即可找到对于任何特定矩形都足够大的所有框。

    考虑到这个数据结构虽然有些复杂,但解决问题很容易。

    构建:

    1. 从一棵空树开始。我们将把矩形放入这棵树中,按 height 排序。
    2. 宽度对矩形进行排序,并按宽度递减的顺序进行处理。
    3. 对于每个矩形,将其添加到树中。对于每个宽度,请记住您创建的最后一棵树。

    查询:

    1. 在上面(3)创建的列表中,二分查找最小宽度>=查询宽度,并检索其树版本。这棵树将包含所有足够宽的矩形,按高度排序。

    2. 从最大高度开始遍历树,直到到达太小的高度。输出你找到的每个矩形。

    您可以在网上找到部分持久性红黑树的实现。它们在函数式语言中很流行,并且被用于大量的计算几何问题。不过,我不知道 python 中已有的实现。

    【讨论】:

      猜你喜欢
      • 2012-07-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-09
      • 2014-08-08
      • 1970-01-01
      • 2021-08-20
      • 2012-06-13
      相关资源
      最近更新 更多