与大多数 3 个矩形一样,一切都将始终在 x-y 轴上定向和对齐,并且没有重叠?你很幸运,有O(n<sup>2</sup>) 3 个这样的矩形集,用O(n<sup>3</sup>) 工作很容易枚举它们。鉴于您正在处理足够数量的黑色矩形以进行视觉显示,因此将它们全部枚举并挑选出最好的一个应该足够快。
首先让我们考虑一下 2 边界矩形的情况,因为它更简单。把图片投影到x轴很容易,把图片投影到y轴也很容易。这两个投影中的至少一个将具有不重叠的可见间隙。因此,我们可以列举划分为两个矩形的可能方法,首先将所有黑色矩形投影到 x 轴上的线段,寻找间隙,并为每个间隙重建我们得到的哪对边界框。然后用 y 轴重复该过程。我们会得到所有的。
现在 3 个边界矩形的情况类似。事实证明,给定 3 个沿 x-y 轴定向的非重叠矩形,x 投影或 y 投影必须有一个可见的间隙。所以我们可以像以前一样做同样的过程,但不是仅仅构造一对边界框,我们尝试构造一个边界框,然后使用相同的算法将另一个边界框分成两个。
(顺便说一句,您很幸运,您只想要 3。这种方法在 4 个边界矩形的情况下会失效。因为这样可能有 4 个边界矩形,使得 x 投影和 y 投影都没有任何可见的间隙。)
那么我们如何取 n 个黑色矩形,将它们投影到一个轴(比如说 x 轴),然后寻找边界矩形的集合?您只需对它们进行排序,构建最大重叠间隔,然后找到差距。像这样:
function find_right_boundaries_of_x_gaps (rectangles) {
var ordered_rect = rectangles.sort(function (r1, r2) { return r1.x1 <=> r2.x2 });
var gaps = [];
var max_right = ordered_rect[0].x2;
for (var i = 0; i < ordered_rect.length; i++) {
if (max_right < ordered_rect[i].x1) {
gaps.push(max_right);
}
if (max_right < ordered_rect[i].x2) {
max_right = ordered_rect[i].x2;
}
}
return gaps;
}
给定一个间隙,很容易找出每边的 2 个矩形边界框。 (如果你有有序的矩形,那就更直接了。)
有了这些部分,您现在应该可以编写代码了。不幸的是,幼稚的方法让您在构建大量重复代码或构建大量大型数据结构之间做出选择。但是,如果您对闭包感到满意,则可以通过两种截然不同的方式解决这两个问题。
第一个是构造闭包,当被调用时,它会遍历你想要的各种数据结构。请参阅http://perl.plover.com/Stream/stream.html 获取灵感。这里的想法是你编写一个函数,它接受一组矩形并返回一个成对的边界框流,然后另一个函数接受一组矩形,获取成对的边界框流,并返回一个三元组流的边界框。然后有一个过滤器接收该流并找到最好的。
另一个是由内而外的。与其返回一个可以遍历可能性的函数,不如传入一个函数,遍历可能性,然后在每种可能性上调用该函数。 (所述函数也可能进行进一步的迭代。)如果您接触过 Ruby 中的块,这种方法可能对您很有意义。
如果您不熟悉闭包,不妨忽略最后几段。