【问题标题】:How to subtract two rectangles?如何减去两个矩形?
【发布时间】:2021-03-04 17:15:50
【问题描述】:

我想知道如何以有效的方式在两个具有“平行边缘”的矩形之间获得 Set Subtraction。提前感谢您的帮助!

问题:我们知道每个矩形可以由四个参数编码。现在,假设我们有 2 个矩形 region1region2,我们想要得到集合减法(又名集合补,集合差 see wikiregion1 - region2,它是一些较小矩形的并集。我们如何才能有效地对这些生成的矩形进行编码?

我的努力:

  1. 一开始,我是通过考虑两个矩形的所有可能位置来做的(通过固定region1和移动region2和许多子情况,至少有10个主要情况)。但当然,这不是一个好策略。

  2. 我发现了一个类似的帖子here,但这并不是我在这里考虑的问题,提供的代码在C#(我不知道)中,答案没有解释。

  3. 然后我在 Math Stack Exchange 中发布 my question 并得到如下有希望的答案:

涉及四个 x 坐标和四个 y 坐标,其中 共同确定9个子矩形;你可以检查一下 他们的中心一一看他们是在region1还是不在 region2.

然后我尝试使用 python(我只知道 Python)对其进行编程。这是我的代码。但我认为它是不干净的、不清楚的和不可读的。此外,由于没有合并具有公共边的矩形,因此效率不高。

def substraction(region1, region2):
    # return region1 \ region2
    # region = [(x1,x2), (y1,y2)]
    assert(len(region1) == 2 and  len(region2) == 2)
    (r1x1, r1x2), (r1y1, r1y2) = region1
    (r2x1, r2x2), (r2y1, r2y2) = region2
    x1, x2, x3, x4 = sorted([r1x1, r1x2, r2x1, r2x2])
    y1, y2, y3, y4 = sorted([r1y1, r1y2, r2y1, r2y2])
    out=[]
    for x in [(x1, x2), (x2, x3), (x3, x4)]:
        for y in [(y1, y2), (y2, y3), (y3, y4)]:
            xm, ym = (x[0]+x[1])/2, (y[0]+y[1])/2
            bool1_x = xm>r1x1 and xm<r1x2
            bool1_y = ym>r1y1 and ym<r1y2
            bool2_x = xm<=r2x1 or xm>=r2x2
            bool2_y = ym<=r2y1 or ym>=r2y2
            if (bool1_x and bool1_y) and (bool2_x or bool2_y):
                out += [ [x, y] ]    
    return out

def test():
    region1=[(0., 1.), (0., 1.)]
    region2=[(0.4, 1.5), (0.4, 0.6)]
    list_rects=substraction(region1, region2)
    print(list_rects)

test()

谁能给出如何改进我的代码的想法。也欢迎新的高效解决方案!谢谢!

【问题讨论】:

  • 这可能是一个经过充分研究的数学问题。您是否尝试过使用谷歌搜索查看已经存在的其他解决方案?
  • Shapely has implemented this functionality。你真的想从头开始编写代码吗?
  • @code 非常感谢您的评论!我做到了,但我找不到我在这里考虑的问题。我认为这只是一个简单的问题,而不是一个很好的数学问题。
  • 更多研究表明,这个问题一点也不简单,但可以是一个有趣的练习,可以同时学习编码和数学。
  • 听起来您希望审查您的“不干净、不清楚和不可读”的代码。这不是那种东西的地方,但也许codereview.stackexchange.com 是。

标签: python math rectangles


【解决方案1】:

一个简单的 C# 解决方案

Еdit:修复 (subtrahend.IsEmpty) 的大小写,使代码不返回零面积矩形。返回触摸矩形的场景见 cmets

    //-------------------------
    //|          A            |
    //|-----------------------|
    //|  B  |   hole    |  C  |
    //|-----------------------|
    //|          D            |
    //-------------------------
    public static IEnumerable<Rectangle> Subtract(this 
        Rectangle minuend,
        Rectangle subtrahend)
    {
        subtrahend.Intersect(minuend);
        //if (subtrahend.IsEmpty)
        //if (subtrahend.Size.IsEmpty)
        if (subtrahend.Width*subtrahend.Height == 0)
        {
            yield return minuend;
            yield break;
        }

        //A
        var heightA = subtrahend.Top - minuend.Top;
        if (heightA > 0)
            yield return new Rectangle(
                minuend.Left,
                minuend.Top,
                minuend.Width,
                heightA);

        //B
        var widthB = subtrahend.Left - minuend.Left;
        if (widthB > 0)
            yield return new Rectangle(
                minuend.Left,
                subtrahend.Top,
                widthB,
                subtrahend.Height);

        //C
        var widthC = minuend.Right - subtrahend.Right;
        if (widthC > 0)
            yield return new Rectangle(
                subtrahend.Right,
                subtrahend.Top,
                widthC,
                subtrahend.Height);

        //D
        var heightD = minuend.Bottom - subtrahend.Bottom;
        if (heightD > 0)
            yield return new Rectangle(
                minuend.Left,
                subtrahend.Bottom,
                minuend.Width,
                heightD);
    }

【讨论】:

  • 我不知道 C,无论如何,谢谢你和 1 upvote
猜你喜欢
  • 1970-01-01
  • 2020-09-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-29
  • 2012-01-29
  • 2016-07-28
  • 1970-01-01
相关资源
最近更新 更多