【问题标题】:JavaScript Merge Intersecting RectanglesJavaScript 合并相交的矩形
【发布时间】:2021-11-26 08:36:49
【问题描述】:

我需要一种方法来合并矩形对象数组(具有x,y,w,h 属性的对象),仅当它们相交时。比如:

merge([{x:0, y:0, w:5, h:5}, {x:1, y:1, w:5, h:5}])

将返回:[{x:0, y:0, w:6, h:6}]


merge([{x:0, y:0, w:1, h:1}, {x:5, y:5, w:1, h:1}])

将返回:[{x:0, y:0, w:1, h:1}, {x:5, y:5, w:1, h:1}]


merge([{x:0, y:0, w:5, h:5}, {x:1, y:1, w:5, h:5}, {x:15, y:15, w:1, h:1}])

将返回:[{x:0, y:0, w:6, h:6}, {x:15, y:15, w:1, h:1}]


如果两个矩形相交,则应以最小边界矩形代替这两个矩形。合并后需要再次检查列表,以防新的 MBR 导致与其他矩形相交。对于我的生活,我无法弄清楚。

【问题讨论】:

  • 这一点都不清楚。您正在传递相同的矩形。如果传递两个相交的不同矩形会发生什么?例如{x:0, y:0, w:2, h:2}, {x:1, y:1, w:2, h:2}要最小包围矩形,交叉点包含的最大矩形,第一个矩形,第二个矩形吗?
  • 在这个例子中,两个对象是相同的,因此实际上不需要合并任何东西。你的要求是什么?对象 b 是否应该覆盖对象 a 中的属性?反之亦然?还是应该是二进制 ANDORXOR
  • 我是个白痴。更新。它应该通过创建一个最小边界矩形来合并它。
  • 好的,好多了,但还是有一些问题。您正在采用最小的封闭矩形。按顺序执行此操作可能会创建以前没有的交叉点。那你想发生什么?像{x:0, y:0, w:10, h:10}, {x:9, y:9, w: 11, h:11}, {x:11, y:0, h:2, w:20} 这样的东西。最后一个应该被视为与前两个相交吗?它不是开始的,但是在将它们合并到封闭的矩形中之后,它会与它相交。
  • OK 将清除它。它将需要再次解析列表以查看是否创建了任何新的交叉点并因此合并它们。

标签: javascript algorithm merge intersection


【解决方案1】:

我不确定这是否会奏效,但我脑子里想的是......

function mergeAll(array) {
  do {
     var newArr = [], didMerge = false, i = 0;

     while (i < array.length) {
        if (intersects(array[i], array[i+1]) {
          newArr.push(merge(array[i], array[i+1]));
          i++;
          didMerge = true;
        }
        i++;
     }
     array = newArr;
  } while (didMerge);
  return array;
}

function intersects(r1, r2) {
    return !( r2.x > r1.x+r1.w
           || r2.x+r2.w < r1.x
           || r2.y > r1.y+r1.h
           || r2.y+r2.h < r1.y
           );
}

function merge(r1, r2) {
   return { x: Math.min(r1.x, r2.x),
            y: Math.min(r1.y, r2.y),
            w: Math.max(r1.w, r2.w),
            h: Math.max(r1.h, r2.h)
          }
}

【讨论】:

  • 进行了一些调整,但成功了!稍后将发布最终代码。干杯!
  • 最后的部分是不是有问题?我不认为 r1.w/h 和 r2.w/h 的最大值会这样做。
【解决方案2】:

这可以通过将问题建模为图形来解决。节点是矩形,只要它们中的任何两个之间有交集,我们就认为这两个节点是由一条边连接的。

我们的目标是将矩形集划分为直接或间接相互连接的组。这基本上是图表的connected component。这可以通过breadth first searchdepth first search 找到。

找到所有组件后,我们只需要找到每个矩形中最高的左上角和最低的右下角即可找到它们的边界框。

可以使用@Marcus 的答案中提供的函数来检查交叉点。

这个过程的总体复杂度是 O(n^2),其中 n 是矩形的数量。

【讨论】:

    【解决方案3】:

    如果有人需要完整的工作示例,请使用 repl 播放 https://repl.it/@anjmao/merge-rectangles 和代码:

    function mergeAll(array) {
        let newArr, didMerge, i;
        do {
            newArr = [];
            didMerge = false;
            i = 0;
            while (i < array.length) {
                const curr = array[i];
                const next = array[i + 1];
                if (intersects(curr, next)) {
                    newArr.push(merge(curr, next));
                    i++;
                    didMerge = true;
                } else {
                    newArr.push(curr);
                }
                i++;
            }
            if (newArr.length > 0) {
              array = newArr; 
            }
        } while (didMerge);
        return array;
    }
    
    function sort(array) {
        array.sort((r1, r2) => {
            if (r1.x === r2.x) {
                return r1.y - r2.y;
            }
            return r1.x - r2.x;
        });
    }
    
    function intersects(r1, r2) {
        if (!r2) {
            return false;
        }
        return !(r2.x > r1.x + r1.w
            || r2.x + r2.w < r1.x
            || r2.y > r1.y + r1.h
            || r2.y + r2.h < r1.y
        );
    }
    
    function merge(r1, r2) {
        const w = r1.w > r2.w ? r1.w : r2.w + (r2.x - r1.x);
        const h = r1.h > r2.h ? r1.h : r2.h + (r2.y - r1.y);
        return {
            x: Math.min(r1.x, r2.x),
            y: Math.min(r1.y, r2.y),
            w: w,
            h: h
        }
    }
    
    mergeAll([{x:0, y:0, w:5, h:5}, {x:1, y:1, w:5, h:5}, {x:15, y:15, w:1, h:1}])
    

    【讨论】:

    • 多余的排序?
    猜你喜欢
    • 2012-11-20
    • 1970-01-01
    • 2012-11-26
    • 2015-06-06
    • 2013-03-31
    • 2023-03-12
    • 2017-09-28
    • 1970-01-01
    相关资源
    最近更新 更多