如何用较小的正方形/矩形填充正方形?

在我工作的办公室里,我们不允许在墙上画画,所以我决定画出正方形和长方形,将一些漂亮的布料贴在墙上,并将它们排列在墙上。

我正在尝试编写一个方法,它将采用我的输入尺寸(9’x 8’8“)和最小/最大尺寸(1’x 3’,2’,4’等)并生成随机模式填充墙壁的正方形和矩形。我尝试手工完成这个,但我对我得到的布局感到不满意,每次我想“随机化”布局需要大约35分钟。

一种解决方案是从x * y方块开始并随机地将方块合并在一起以形成矩形。 你需要给不同大小的方块赋予不同的权重,以防止算法最终得到大量的小矩形(即大矩形应该有更高的机会被选中进行合并直到它们变得太大)。

听起来像树图

另一个想法:

1. Randomly generate points on the wall Use as many points as the number of rectangles you want Introduce sampling bias to get cooler patterns 2. Build the kd-tree of these points 

kd树将以多个矩形分割空间。 可能有太多的结构,你想要的,但它仍然是一个整洁的怪异算法。

(见: http : //en.wikipedia.org/wiki/Kd-tree )

编辑:刚刚看过JTreeMap,看起来有点像这是它的作用。

如果你正在谈论一个纯粹的编程问题;)有一种称为Bin Packing的技术,它试图将一些二进制数据包装到可能的最小区域。 那里有大量的材料:

http://en.wikipedia.org/wiki/Bin_packing_problem

http://mathworld.wolfram.com/Bin-PackingProblem.html

http://www.cs.sunysb.edu/~algorith/files/bin-packing.shtml

所以你’可以’创建一大堆随机方块并通过bin packer运行它来生成你的模式。

我自己没有实现bin打包算法,但是我已经看到它由Nike网站的同事完成。 祝你好运

既然你可以选择矩形的大小,这不是一个难题。

我会说你可以做一些简单的事情:

   选择当前不在矩形内的(x,y)坐标。
   选择第二个(x,y)坐标,以便在两者之间绘制矩形
      两个坐标,它不会重叠任何东西。 边界框
      有效点仅由最近的矩形墙限定。
   画出那个矩形。
   重复,直到你说有90%的面积覆盖。 那时候你
      可以停止,或用大矩形填充剩余的孔
      尽可能。

参数化点的生成,然后制作遗传算法可能会很有趣。 健身function将是你喜欢的安排 – 它会为你绘制数百个安排,你会按照1-10的等级评定。 然后它将采取最好的并调整它们,并重复,直到你得到你真正喜欢的安排。

箱包装还是方包装?

Bin包装: http : //www.cs.sunysb.edu/~algorith/files/bin-packing.shtml

方形包装: http : //www.maa.org/editorial/mathgames/mathgames_12_01_03.html

这听起来更像是一个古老的学校随机方形绘画演示,大约8位计算日,特别是如果你不介意重叠。 但如果你想变得特别怪异,可以创建随机方块并解决包装问题。

建立Philippe Beaudoin的答案。

您也可以使用其他语言的树形图实现。 在Ruby中使用RubyTreeMap,你可以做到

 require 'Treemap' require 'Treemap/image_output.rb' root = Treemap::Node.new 0.upto(100){|i| root.new_child(:size => rand) } output = Treemap::ImageOutput.new do |o| o.width = 800 o.height = 600 end output.to_png(root, "C:/output/test.png") 

然而,它对矩形进行排序,因此它看起来不是很随机,但它可能是一个开始。 有关详细信息,请参阅rubytreemap.rubyforge.org/docs/index.html

我会以缓慢的方式生成所有内容。如果在任何时候你达到一个点,你的解决方案被certificate是“无法解决的”(IE,不能在剩下的中间放置任何方块以满足约束),转到早期的草案并改变一些方格,直到找到一个快乐的解决方案。

伪代码看起来像:

 public Board GenerateSquares(direction, board, prevSquare) { Rectangle[] rs = generateAllPossibleNextRectangles(direction, prevSquare, board); for(/*all possible next rectangles in some random order*/)){ if(board.add(rs[x]){ //see if you need to change direction) Board nBoard = GenerateSquares(direction, board, rs[x]); if(nBoard != null) return nBoard; //done else board.remove(rs[x]); } } //all possibilities tried, none worked return null; } 

}

我建议:

首先设置一个具有四个顶点的多边形,以便以不同的大小(最大为maxside)矩形块进行食用:

 public double[] fillBoard(double width, double height, double maxside) { double[] dest = new int[0]; double[] poly = new int[10]; poly[0] = 0; poly[1] = 0; poly[2] = width; poly[3] = 0; poly[4] = width; poly[5] = height; poly[6] = 0; poly[7] = height; poly[8] = 0; poly[9] = 0; ... return dest; /* x,y pairs */ } 

然后选择一个随机顶点,在该行的2 X最大值范围内找到多边形线。 找到所有水平线的所有垂直线和y值的x值。 为选择每个x和y值的“良好”创建评级,并为这些值之间的值生成等式的等式。 优良度测量为减少剩余多边形中的线数。 使用伪随机生成器为两个x坐标或两个y坐标之间的每个值范围生成三个选项。 在加权平均基础上评估和选择x对和y对的对,倾向于良好的选择。 通过从多边形arrays切割其形状并将矩形坐标添加到dest数组,将新矩形应用于列表。

问题没有说明最小的侧面参数。 但是如果需要的话,算法应该(在碰到间隙太小的情况下)不要在选择列表中包含太小的候选者(偶尔会使它们变空)并在某个半径范围内取消选择一些周围的矩形。大小的问题,并执行该区域的新再生尝试,并希望问题区域,直到满足标准。 如果较小的切换中继失败,则递归可以逐渐移除较大的区域。

编辑

做一些命中测试以消除潜在的重叠。 在开始打字前吃一些菠菜。 ;)

  1. 定义输入区域;
  2. 在整个高度的几个随机水平位置绘制垂直线;
  3. 在整个宽度的几个垂直位置绘制水平线;
  4. 将一些“列”向上或向下移动任意数量;
  5. 左右移动一些“行”任意数量(可能需要细分一些单元格以获得完整的水平接缝;
  6. 按照美学要求去除接缝。

这种图形方法与Brian的答案有相似之处。