我需要一种方法来合并一个矩形对象数组(具有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导致与其他矩形交叉,则需要在合并后再次检查该列表。对于我的生活,我无法理解。
答案 0 :(得分:7)
我不确定这是否会起作用,但我不知道......
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)
}
}
答案 1 :(得分:2)
这可以通过将问题建模为图表来解决。节点是矩形,每当它们中的任何两个之间存在交叉时,我们认为这两个节点通过边连接。
我们的目标是将矩形集分成直接或间接相互连接的组。这基本上是图的connected component。这可以使用breadth first search或depth first search找到。
找到所有组件后,我们只需找到每个组件中最高的左上角和最右下角,找到它们的边界框。
可以使用@Marcus'答案中提供的功能来检查交叉点。
此过程的总体复杂度为O(n ^ 2),其中n是矩形的数量。
答案 2 :(得分:0)
如果有人需要完全正常工作的例子,请在这里重新播放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}])