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

C# 如何用较小的正方形/矩形填充正方形?,c#,algorithm,drawing,C#,Algorithm,Drawing,在我工作的办公室里,我们不允许粉刷墙壁,所以我决定画出正方形和长方形,在它们上面贴上一些漂亮的织物,然后把它们排列在墙上 我正在尝试编写一个方法,该方法将采用我的输入尺寸(9'x 8'8”)和最小/最大尺寸(1'x 3',2',4',等等)然后生成一个正方形和矩形的随机图案来填充墙壁。我试着用手来做,但我对我得到的布局不满意,每次我想“随机”布局大约需要35分钟。如果你说的是一个纯编程问题;)有一种叫做装箱的技术,它试图打包一个麻木的东西将垃圾箱的数量减少到尽可能小的区域。那里有大量的材料:

在我工作的办公室里,我们不允许粉刷墙壁,所以我决定画出正方形和长方形,在它们上面贴上一些漂亮的织物,然后把它们排列在墙上


我正在尝试编写一个方法,该方法将采用我的输入尺寸(9'x 8'8”)和最小/最大尺寸(1'x 3',2',4',等等)然后生成一个正方形和矩形的随机图案来填充墙壁。我试着用手来做,但我对我得到的布局不满意,每次我想“随机”布局大约需要35分钟。

如果你说的是一个纯编程问题;)有一种叫做装箱的技术,它试图打包一个麻木的东西将垃圾箱的数量减少到尽可能小的区域。那里有大量的材料:

所以你“可以”创建一个随机方块负载,并运行它通过一个垃圾箱包装机生成你的模式


我自己还没有实现过装箱算法,但我看到一位同事在Nike网站上完成了。祝你好运,因为你可以选择矩形的大小,这不是一个困难的问题

我想说,你可以做一些简单的事情,比如:

Pick an (x,y) coordinate that is not currently inside a rectangle. Pick a second (x,y) coordinate so that when you draw a rectangle between the two coordinates, it won't overlap anything. The bounding box of valid points is just bounded by the nearest rectangles' walls. Draw that rectangle. Repeat until, say, you have 90% of the area covered. At that point you can either stop, or fill in the remaining holes with as big rectangles as possible. 拾取当前不在矩形内的(x,y)坐标。 拾取第二个(x,y)坐标,以便在 这两个坐标,它不会重叠任何东西 有效点仅以最近的矩形墙为边界。 画那个长方形。 重复,直到,比方说,你已经覆盖了90%的面积 可以停止,也可以用同样大的矩形填充剩余的孔 尽可能的。
将点的生成参数化,然后制作一个遗传算法,这可能会很有趣。适应度函数将是您对排列的喜爱程度-它将为您绘制数百个排列,您将按照1-10的比例对它们进行评分。然后选择最好的排列并对其进行调整,然后重复,直到您获得排列你真的喜欢。

箱式包装还是方形包装

箱子包装:

方形包装:


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

听起来像是一个

我会以螺旋的方式慢慢生成所有东西。如果你在任何时候如果你的解决方案被证明是“无法解决的”(即,不能在剩余的中间放置任何正方形以满足约束条件),请转到先前的草稿并更改一些正方形,直到找到满意的解决方案

伪代码看起来像:

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;
}

}

一种解决方案是从x*y正方形开始,随机将正方形合并在一起形成矩形。您需要为不同大小的正方形赋予不同的权重,以防止算法以大量小矩形结束(也就是说,在大矩形变得太大之前,可能会有更高的机会被选中进行合并)。

我建议:

首先,设置一个多边形,该多边形有四个顶点,可以在不同大小(最大为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 maxside内找到多边形直线。 查找所有垂直线的x值和所有水平线的y值。为“优点”创建评级"选择每个x和y值的方法,以及为值之间的值生成评级的公式。衡量优劣的方法是减少剩余多边形中的线数。使用伪随机生成器为两个x坐标或两个y坐标之间的每个值范围生成三个选项。对x和y值对进行评级并选择在加权平均的基础上,倾向于好的选项。通过从多边形数组中剪切新矩形的形状并将矩形坐标添加到dest数组中,将其应用到列表中

问题并没有说明最小的边参数。但如果需要,算法应该(在遇到一个间隙太小的障碍时)在选择列表中不包含太小的候选项(有时会使它们为空)在问题的某个半径范围内,取消选择多个大小为的周围矩形,并对该区域(希望是问题区域)执行新的重新生成尝试,直到满足标准。如果较小的分片中继失败,递归可以逐渐删除较大的区域

编辑

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

另一个想法:

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树将空间分割为多个矩形。你想要的东西可能有太多的结构,但它仍然是一个整洁的极客算法

(见:)


编辑:刚刚看了JTreeMap,看起来有点像它所做的。

以Philippe Beaudoin的答案为基础构建

您也可以使用其他语言的treemap实现。在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

  • 定义输入区域
  • 在多个随机水平位置绘制垂直线,穿过整个高度
  • 在整个宽度的几个垂直位置绘制水平线
  • 将某些“列”上下移动任意数量
  • 将某些“行”向左或向右移动任意数量(可能需要细分某些单元格以获得完整的水平接缝
  • 根据美观要求去除接缝

  • 这种图形化方法与。

    这根本不是答案,但我怀疑使用十进制单位会容易得多。;)如果他们只让你粉刷墙壁或聘请室内设计师,而不是花时间编程,他们的工作效率会更高