将矩形拆分为n个大小相等的矩形

时间:2011-04-08 12:13:59

标签: python algorithm geometry

我正在寻找一种算法,将矩形(比方说1000x800)分割为n(或更多,但尽可能少的额外矩形)在该矩形内同样大小的矩形,因此使用了所有空间。小矩形也应该尽量接近原始的长宽比。

例如:

+---------------+
|               |
|               |
|               |
+---------------+

分割n = 2:

+---------------+
|               |
+---------------+
|               |
+---------------+

分割n = 3

+-------+-------+
|       |       |
+-------+-------+
|       |       |
+---------------+

有这样的算法吗?理想情况下我想在Python中使用它,但实际上任何语言都可以,因为我应该能够翻译它...

编辑:

一些额外的信息:

目标曲面将是一个浏览器窗口,因此曲面将大致 4:3或16:9或其他常用尺寸。矩形由像素组成。宽高比保证是整数。

与纵横比约束相比,较少过量的矩形略有优势。

3 个答案:

答案 0 :(得分:2)

(我假设,也许是错误的,你的矩形是无限可分的,而不是由离散的像素组成。)

你可以通过让m = ceil(sqrt(n))并在每一边使用m个片段来获得完全正确的宽高比,在浪费的矩形中花费一些成本。

否则,您正在寻找接近sqrt(n)的p,q,使得pq> = n和p,q彼此接近。 p,q的最佳选择当然取决于您是否愿意将废物与不准确性进行权衡。你似乎不太可能想把p,q放在远离sqrt(n)的地方,因为这样做会给你一个很大的形状错误。所以我想你想要这样的东西:

p = ceiling(sqrt(n))
best_merit_yet = merit_function(p,p,0)
best_configuration_yet = (p,p)
for p from floor(sqrt(n)) downward:
  # we need pq >= n and q as near to p as possible, which means (since p is too small) as small as possible
  q = ceiling(n/p)
  if max(merit_function(n/p,n/q,0), merit_function(n/q,n/p,0)) < best_merit_yet:
    break
  n_wasted = p*q-n
  merit1 = merit_function(n/p,n/q,n_wasted)
  merit2 = merit_function(n/q,n/p,n_wasted)
  if max(merit1,merit2) > best_merit_yet:
    if merit1 > merit2:
      best_configuration_yet = (p,q)
      best_merit_yet = merit1
    else:
      best_configuration_yet = (q,p)
      best_merit_yet = merit2

并且希望非常错误的形状是非常糟糕的事实将意味着你实际上不需要进行循环的多次迭代。

在这里,merit_function应该体现你对废物形状进行折衷的偏好。

答案 1 :(得分:1)

使用此功能可获得2个数字作为列表:

def divide_equally(n):
    if (n<3):
        return [n, 1]
    result = list()
    for i in range(1, int(n ** 0.5) + 1):
       div, mod = divmod(n, i)
       #ignore 1 and n itself as factors
       if mod == 0 and i != 1 and div != n:
           result.append(div)
           result.append(i)
    if len(result)==0: # if no factors then add 1
        return divide_equally(n+1)
    return result[len(result)-2:]

例如:

print divide_equally(1)
print divide_equally(50)
print divide_equally(99)
print divide_equally(23)
print divide_equally(50)

将给出

[1, 1]
[10, 5]
[11, 9]
[6, 4]  # use the next even number (24)
[10, 5] # not [25, 2] use the 2 closest numbers 

答案 2 :(得分:0)

编辑:第二个想法:

var countHor = Math.Floor(Math.Sqrt(n));
var countVer = Math.Ceil(n / countHor);
var widthDivided = widthTotal / countVer;
var heightDivided = heightTotal / countHor;

虽然结果取决于您更喜欢矩形比率或额外矩形数量(例如,对于n = 14,应该是2x7或3x5,对于n = 7,应该是3x3还是2x4)

由于一些消耗,第一个想法是错误的:

如果要获得最小数量的相等矩形,则应使用sqrt操作。例如,如果n = 9,则它将是3x3矩形(垂直2行,水平2行)。如果n = 10,则将3x4矩形作为floor(sqrt(10))x ceil(sqrt(10))=&gt; 3x4(垂直2行,水平3行或其他)。

这只是一般算法的概念,根据您的要求,您应该构建正确的算法。

新矩形的大小如下:

var widthDivided = widthTotal / Math.Floor(Math.Sqrt(count));
var heightDivided = heightTotal / Math.Ceil(Math.Sqrt(count));

这是类似的任务,但它不会返回最小值: Algorithm to split rectangle into n smaller rectangles and calculate each center