﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-wang37921</title><link>http://www.cppblog.com/wang37921/</link><description /><language>zh-cn</language><lastBuildDate>Tue, 07 Apr 2026 07:04:49 GMT</lastBuildDate><pubDate>Tue, 07 Apr 2026 07:04:49 GMT</pubDate><ttl>60</ttl><item><title>【译】构建CCS Sprites快而优的矩形打包算法</title><link>http://www.cppblog.com/wang37921/archive/2014/10/24/208669.html</link><dc:creator>王聪</dc:creator><author>王聪</author><pubDate>Fri, 24 Oct 2014 10:11:00 GMT</pubDate><guid>http://www.cppblog.com/wang37921/archive/2014/10/24/208669.html</guid><wfw:comment>http://www.cppblog.com/wang37921/comments/208669.html</wfw:comment><comments>http://www.cppblog.com/wang37921/archive/2014/10/24/208669.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/wang37921/comments/commentRss/208669.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/wang37921/services/trackbacks/208669.html</trackback:ping><description><![CDATA[<h1><span style="font-size: 22pt; font-family: 宋体;">构建CCS&nbsp;Sprites快而优的矩形打包算法</span></h1><h2><span style="font-size: 16pt; font-family: 黑体;">介绍</span></h2><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">（译者注：略）</span></p><h2><span style="font-size: 16pt; font-family: 黑体;">内容</span></h2><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">（译者注：略）</span></p><h2><span style="font-size: 16pt; font-family: 黑体;">安装</span></h2><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">（译者注：略）</span></p><h2><span style="font-size: 16pt; font-family: 黑体;">简单的解决方案</span></h2><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">这有几个简单的方案讲述如何打包多个矩形到一个封闭的矩形中：</span></p><p style="margin-left:21.0000pt; text-indent:-21.0000pt; margin-bottom:0pt; margin-top:0pt; "><span style="font-size:10.5000pt; font-family:'Wingdings'; ">l&nbsp;</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">你可以将所有矩形在水平方向上一字排开，就像这样：</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><img src="http://www.cppblog.com/images/cppblog_com/wang37921/图片1.png" border="0" alt="" /><br /></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:12.0000pt; font-family:'宋体'; ">这很简单也很快，并且可以在所有矩形高度一致时表现的很好。</span></p><p style="margin-left:21.0000pt; text-indent:-21.0000pt; margin-bottom:0pt; margin-top:0pt; "><span style="font-size:10.5000pt; font-family:'Wingdings'; ">l&nbsp;</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">或者你可以在水平方向上排列，就像这样：</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><img src="http://www.cppblog.com/images/cppblog_com/wang37921/图片2.png" border="0" alt="" /><br /></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:12.0000pt; font-family:'宋体'; ">这依旧简单快捷，并且当所有矩形宽度一致时表现良好。</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:12.0000pt; font-family:'宋体'; ">但是，这些方案在这些矩阵拥有不同的宽度和高度时留下大量被浪费的空间。这很烦人。所以接下来我们将关注在打包不同宽度和高度矩形时将这种浪费最小化，当然也要尽可能的快和简单。</span></p><h2><span style="font-size: 16pt; font-family: 黑体;">基本算法</span></h2><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">打包多个矩形到尽可能小的封闭矩形的基本算法在Richard&nbsp;E.&nbsp;Korf的文章有有被描述：</span><a href="http://www.aaai.org/Papers/ICAPS/2003/ICAPS03-029.pdf"><span style="color: #0000ff; font-family: 'Times New Roman';">Optimal&nbsp;Rectangle&nbsp;Packing:&nbsp;Initial&nbsp;Results</span></a><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">。</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="font-size:10.5000pt; font-family:'宋体'; ">1.</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">根据高度对矩形进行排序，最高的排第一。</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="font-size:10.5000pt; font-family:'宋体'; ">2.</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">闭合矩形初始设置为：高度为最高矩形的高度，宽度无限大。</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="font-size:10.5000pt; font-family:'宋体'; ">3.</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">将矩形一个个的放入封闭矩形中，由最高的矩形开始，到最矮的矩形结束。放置每个矩形时尽可能靠左。</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; background:#ffff00; font-family:'宋体'; ">如果有多个左边位置，使用最高的那个</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">（If&nbsp;there&nbsp;are&nbsp;several&nbsp;left&nbsp;most&nbsp;locations,&nbsp;use&nbsp;the&nbsp;highest&nbsp;one&nbsp;）。比如：</span></p><p style="margin-left:42.0000pt; text-indent:-21.0000pt; margin-bottom:0pt; margin-top:0pt; "><span style="font-size:12.0000pt; font-family:'宋体'; ">a)&nbsp;<img src="http://www.cppblog.com/images/cppblog_com/wang37921/图片3.png" width="138" height="48" alt="" /></span></p><p style="margin-left:42.0000pt; text-indent:-21.0000pt; margin-bottom:0pt; margin-top:0pt; "><span style="font-size:12.0000pt; font-family:'宋体'; ">b)&nbsp;<img src="http://www.cppblog.com/images/cppblog_com/wang37921/图片4.png" width="138" height="48" alt="" /></span></p><p style="margin-left:42.0000pt; text-indent:-21.0000pt; margin-bottom:0pt; margin-top:0pt; "><span style="font-size:12.0000pt; font-family:'宋体'; ">c)&nbsp;<img src="http://www.cppblog.com/images/cppblog_com/wang37921/图片5.png" width="138" height="48" alt="" /></span></p><p style="margin-left:42.0000pt; text-indent:-21.0000pt; margin-bottom:0pt; margin-top:0pt; "><span style="font-size:12.0000pt; font-family:'宋体'; ">d)&nbsp;<img src="http://www.cppblog.com/images/cppblog_com/wang37921/图片6.png" width="138" height="48" alt="" /></span></p><p style="margin-left:42.0000pt; text-indent:-21.0000pt; margin-bottom:0pt; margin-top:0pt; "><span style="font-size:12.0000pt; font-family:'宋体'; ">e)&nbsp;<img src="http://www.cppblog.com/images/cppblog_com/wang37921/图片7.png" width="138" height="48" alt="" /></span></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="font-size:10.5000pt; font-family:'宋体'; ">4.</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">让闭合矩形的宽度等于弄好的所有矩形的总宽度。即：将闭合矩形的右边缘向左移动，直到接触到最右边矩形的右边缘。这样的话，闭合矩形宽度正合适。</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="font-size:10.5000pt; font-family:'宋体'; ">5.</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">你已经将所有矩形放置在闭合矩形内了吗？如果这样的话：</span></p><p style="margin-left:42.0000pt; text-indent:-21.0000pt; margin-bottom:0pt; margin-top:0pt; "><span style="font-size:10.5000pt; font-family:'Wingdings'; ">l&nbsp;</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">如果你得到的这个闭合矩形是目前最小的且&#8220;成功&#8221;的，将它保存起来。</span></p><p style="margin-left:42.0000pt; text-indent:-21.0000pt; margin-bottom:0pt; margin-top:0pt; "><span style="font-size:10.5000pt; font-family:'Wingdings'; ">l&nbsp;</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">试着宽度减一来获取更小的闭合区域。</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="font-size:10.5000pt; font-family:'宋体'; ">6.</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">然而，如果你没有全部将矩形放置在闭合矩形内，很显然闭合矩形小了。如果这样的话，将高度加一。（</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; background:#ffff00; font-family:'宋体'; ">译者注：就这样重复执行放置矩形到闭合矩形内，直到得到一个原始最佳宽度减一&#215;原始高度不断加一加到能将所有矩形都放入这个新闭合矩形内，其实并不是笨笨的加一，往下看，改进基本算法部分有提到这步具体做法</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">）请注意，减宽度加高度实际上意味着我们将闭合矩形的范围从矮宽到高瘦。比如，当宽度被减少、高度被增加几次后，你可能会得到如下的序列：</span></p><p style="margin-left:42.0000pt; text-indent:-21.0000pt; margin-bottom:0pt; margin-top:0pt; "><span style="font-size:12.0000pt; font-family:'宋体'; ">a)&nbsp;<img src="http://www.cppblog.com/images/cppblog_com/wang37921/图片8.png" width="75" height="83" alt="" /></span></p><p style="margin-left:42.0000pt; text-indent:-21.0000pt; margin-bottom:0pt; margin-top:0pt; "><span style="font-size: 10.5pt; font-family: 'Times New Roman';">b)&nbsp;<img src="http://www.cppblog.com/images/cppblog_com/wang37921/图片9.png" width="75" height="83" alt="" /></span></p><p style="margin-left:42.0000pt; text-indent:-21.0000pt; margin-bottom:0pt; margin-top:0pt; "><span style="font-size:12.0000pt; font-family:'宋体'; ">c)&nbsp;<img src="http://www.cppblog.com/images/cppblog_com/wang37921/图片10.png" width="75" height="83" alt="" /></span></p><p style="margin-left:42.0000pt; text-indent:-21.0000pt; margin-bottom:0pt; margin-top:0pt; "><span style="font-size: 12pt; font-family: 宋体;">d)&nbsp;<img src="http://www.cppblog.com/images/cppblog_com/wang37921/图片11.png" width="75" height="83" alt="" /></span></p><p style="margin-left:42.0000pt; text-indent:-21.0000pt; margin-bottom:0pt; margin-top:0pt; "><span style="font-size:12.0000pt; font-family:'宋体'; ">e)&nbsp;<img src="http://www.cppblog.com/images/cppblog_com/wang37921/图片12.png" width="75" height="83" alt="" /></span></p><p style="margin-bottom:0pt; margin-top:0pt; ">&nbsp;</p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="font-size:10.5000pt; font-family:'宋体'; ">7.</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">如果你得到的闭合矩形的总面积（宽&#215;高）比所有将放入其中的矩形的面积之和还要小，那这明显不是一个可行的闭合矩形。高度增加一直到你得到一个可行的闭合矩形。然后进入到下一步。</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="font-size:10.5000pt; font-family:'宋体'; ">8.</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">如果你获得的这个闭合矩形比迄今为止最好的闭合矩形要大，那么对它进行测试并无意义。宽度减一然后重复第七步来确保不是小了，否则进入下一步。</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="font-size:10.5000pt; background:#ffff00; font-family:'宋体'; ">9.</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; background:#ffff00; font-family:'宋体'; ">如果你的新的闭合区域比最宽的矩形要窄，你就可以停下了，并且汇报你得到的最佳闭合矩形。这是因为我们这个算法从不会增加闭合矩形的宽度，并且如果最宽矩形都放不下，这明显不需要再测试这个闭合矩形了。（If&nbsp;your&nbsp;new&nbsp;enclosing&nbsp;rectangle&nbsp;is&nbsp;narrower&nbsp;than&nbsp;the&nbsp;widest&nbsp;rectangle,&nbsp;you&nbsp;can&nbsp;stop&nbsp;now,&nbsp;and&nbsp;report&nbsp;the&nbsp;best&nbsp;enclosing&nbsp;rectangle&nbsp;you&nbsp;found&nbsp;so&nbsp;far.&nbsp;This&nbsp;is&nbsp;because&nbsp;the&nbsp;algorithm&nbsp;never&nbsp;increases&nbsp;the&nbsp;width&nbsp;of&nbsp;the</span>&nbsp;<span style="mso-spacerun:'yes'; font-size:10.5000pt; background:#ffff00; font-family:'宋体'; ">enclosing&nbsp;rectangle,&nbsp;and&nbsp;if&nbsp;the&nbsp;widest&nbsp;rectangle&nbsp;won't&nbsp;fit,&nbsp;there&nbsp;is&nbsp;obviously&nbsp;no&nbsp;point&nbsp;in&nbsp;testing&nbsp;the</span>&nbsp;<span style="mso-spacerun:'yes'; font-size:10.5000pt; background:#ffff00; font-family:'宋体'; ">enclosing&nbsp;rectangle.）</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="font-size:10.5000pt; font-family:'宋体'; ">10.</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">现在你的新闭合矩形既不太小，也不太大，返回第三步去看看你是否可以将所有矩形放进去。</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">这个算法已经在下载工程Mapper中的类MapperOptimalEfficiency的函数Mapping中实现了。</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">稍后我们将看看如何将这个基本算法做的更快些。但是首先让我们看看如何将矩形放入闭合区域中，最主要的是如何记录已放入的矩形来防止新加入矩形与他们重叠。</span></p><h2><span style="font-size: 16pt; font-family: 黑体;">在一个给定的闭合矩形内安放矩形而不与其他矩形重叠</span></h2><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">上面基本算法中的第三步写到&#8220;将矩形一个个的放入闭合矩形内，从最高的矩形开始，最矮的结束。放置每个矩形时尽可能的靠左，如果有好几个左边位置，用最高的那个。&#8221;</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">为了找到最左最高的位置来放置一个给定宽度和高度矩形而不与其他矩形重叠，我们需要用一些数据结构来记录闭合矩形中已被占用的区域。并且这个数据结构必须既简单（这样不容易出错）又能快速找到矩形可以被放置的那个最左最高位置。</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">可以使用一个二维布尔数组，每个格子代表闭合区域中的一个像素。每个布尔标记这个像素是否被占用还是空闲。然而，当你为一个矩形找空时需要访问很多像素，这个方案简单但效率低下。</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">另一个方案，可以保存闭合矩形中每个矩形的宽和高以及他们的X/Y方向的偏移。这个数据结构比起二维像素数据拥有更少的成员变量，但是在空间足够的情况下，计算出这个最左最高的位置使用这个结构将既复杂又慢。</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">我想出的解决方法是：使用一个动态的二维布尔数组表示占用或空闲，但是为每行存储一个高度，每列存储一个宽度，这样列数和行数可以保持在最小。这样既减少复杂度又降低了需要访问的格子数（和因此花费的时间）。下面是添加矩形时这个方法如何工作的（白色格子是未被占用，绿色格子是被占用，暗绿色格子是刚被最后一次添加矩形占用的）：</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="font-size:10.5000pt; font-family:'宋体'; ">1.</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">首先，只有一行和闭合矩形一样高，一列和闭合矩形一样宽。这意味着只有一个格子。</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><img src="http://www.cppblog.com/images/cppblog_com/wang37921/图片13.png" width="150" height="166" alt="" /><br /></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="font-size:10.5000pt; font-family:'宋体'; ">2.</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">当添加第一个矩形时，找出最左最高的格子很轻松，因为这儿只有一个。确保他对于这个矩形足够大也很简单。所以我们继续，并把它放置在格子的左上角。</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">我们现在有个格子被部分占用，部分没有被占用。然而一个格子只能是一种状态。为了解决这个问题，将单行分开、单列分开，这样我们就获得了四个格子，这样他们要么被占用，要么没有被占用：</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><img src="http://www.cppblog.com/images/cppblog_com/wang37921/图片14.png" width="150" height="166" alt="" /><br /></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="font-size:10.5000pt; font-family:'宋体'; ">3.</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">该添加第二个矩形了。首先检查最左边的列。从上到下遍历这个列中所有的格子直到你找到一个空闲的格子。然后检查是否能将矩形放在那儿。</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">最左列有一个空闲格，但是垂直方向上不够放下这个矩形。那么在右边一列如法炮制的查找。</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">第二列中，最高的那个格子是空间的，并且足够放置矩形，那么这很简单。将矩形放在那。和第一个格子放置时一样，矩形相对于格子比较小，导致一个格子部分被占用，部分未占用。所以分割该格子的行和列来确保格子又回到不是被占用就是未被占用的状态。注意结果，第一个矩形所占用的格子现在被划分为二了，这没关系的。</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><img src="http://www.cppblog.com/images/cppblog_com/wang37921/图片15.png" width="150" height="166" alt="" /><br /></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="font-size:10.5000pt; font-family:'宋体'; ">4.</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">第三个矩形也走同样的流程。然而，因为这个矩形有点矮，所以最左列有足够的空间来放置他。再一次，在这个格子中相交的行列被分割了，来取保所有格子要么是占用要么是未被占用。</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><img src="http://www.cppblog.com/images/cppblog_com/wang37921/图片16.png" width="150" height="166" alt="" /><br /></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="font-size:10.5000pt; font-family:'宋体'; ">5.</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">第四个矩形走同样的流程。如果最左列剩余垂直空间不足，那就在他右边试试。最左列最高的那个格子足够高来放置矩形，但是不够宽。所以测试右边的列看是不是有足够空闲的格子来安放矩形。可以看到起始列和他右边的列组合起来在水平方向上就有足够的空间安放这个矩形，也就是说这个矩形可以用两个格子来放置。再一次格子在行列上被分割，确保格子被占用或非占用。</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><img src="http://www.cppblog.com/images/cppblog_com/wang37921/图片17.png" width="150" height="166" alt="" /><br /></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="font-size:10.5000pt; font-family:'宋体'; ">6.</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">第五个矩形，依旧从左到右的检查列。第二列有一个空闲格，但是对于该矩形在垂直方向上没有足够的空间。第三列有两个不相连的空闲格子，但是他俩高度都不够，并且垂直空间上也无法和其他格子结合凑足垂直空间来放置矩形。</span></p><p style="margin-bottom:0pt; margin-top:0pt; text-align:justify; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">在第四列，有一个空间格子，他既不够高也不够宽来安放矩形。所以检查右边列的格子和下面行的格子看是不是有足够空闲的格子可以组合来容纳矩形。在这种情况下，这证明是可行的。再一次，发生了行列分割来保证格子占用或非占用的唯一性。</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><img src="http://www.cppblog.com/images/cppblog_com/wang37921/图片18.png" width="150" height="166" alt="" /><br /></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">通过运行下载文件中的网站，你可以看到更多的例子。他也演示了不是所有矩形都能放置的情况。</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">找到可以放置矩形的最左最高格子和检查周围格子的代码在下载中的Mapper工程的Canvas类中可以找到。二维动态数组在DynamicTwoDimensionalArray类中实现。因为他被经常使用，这个类为了性能被高度优化，尤其是分割行和列时。</span></p><h2><span style="font-size: 16pt; font-family: 黑体;">对基本算法的改进</span></h2><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">当学习下载的test&nbsp;site中生成的测试例子时，下面的改进会很明显。在写改进在下载的代码中有的。我在文献中没有找到这些改进的方法，所有你可以先读一下他们：</span></p><p style="margin-left:21.0000pt; text-indent:-21.0000pt; margin-bottom:0pt; margin-top:0pt; "><span style="font-size:10.5000pt; font-family:'Wingdings'; ">l&nbsp;</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">减小封闭区域宽度后，增加足够的高度</span></p><p style="margin-left:21.0000pt; text-indent:-21.0000pt; margin-bottom:0pt; margin-top:0pt; "><span style="font-size:10.5000pt; font-family:'Wingdings'; ">l&nbsp;</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">放置所有矩形失败后，增加足够的高度</span></p><p style="margin-left:21.0000pt; text-indent:-21.0000pt; margin-bottom:0pt; margin-top:0pt; "><span style="font-size:10.5000pt; font-family:'Wingdings'; ">l&nbsp;</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">通过设置效率的上限获得加速</span></p><h3><span style="font-size: 16pt; font-family: 宋体;">减小封闭区域宽度后，增加足够的高度</span></h3><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">看下下面那个一轮基本算法生成的闭合矩形：</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><img src="http://www.cppblog.com/images/cppblog_com/wang37921/图片19.png" width="91" height="120" alt="" /><br /></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">根据基本算法，你应该将闭合矩形的宽度减一，然后试着重新安放所有矩形。然而，如果你简单的将宽度减一，你知道暗绿色矩形一定会超出闭合矩形的右手边界，对它来说无处容身了就，所以下次尝试安放所有矩形时一定会失败。</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">另外，算法说当失败的时候将闭合矩形的高度加一。但是，因为暗绿色矩形的高度是十个像素，明显高度加一是不够的。所以基本算法接下来一定会进行十次失败的尝试去安放所有矩形，这很费也没啥必要。</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">可以通过记录接触到闭合矩形右手边界最高矩形的高度来进行优化。如果你成功安放好所有矩形并将闭合矩形的宽度减一后，可以将闭合矩形的高度加上超出闭合矩形右方的最高矩形的高度。这样算法可以在新的闭合矩形内为超出右方的最高矩形找到新的位置：</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><img src="http://www.cppblog.com/images/cppblog_com/wang37921/图片20.png" width="76" height="140" alt="" /><br /></p><h3><span style="font-size: 16pt; font-family: 宋体;">放置所有矩形失败后，增加足够的高度</span></h3><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">看看下面的序列。使用该算法安放好四个矩形后，放置第五个矩形时失败了。</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">1</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">	</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">	</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">	</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">	</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">2</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">	</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">	</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">	</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">	</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">3</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">	</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">	</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">	</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">	</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">4</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">	</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">	</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">	</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">放置矩形失败</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><img src="http://www.cppblog.com/images/cppblog_com/wang37921/图片21.png" width="92" height="240" alt="" />&nbsp;<img src="http://www.cppblog.com/images/cppblog_com/wang37921/图片22.png" width="92" height="240" alt="" />&nbsp;<img src="http://www.cppblog.com/images/cppblog_com/wang37921/图片23.png" width="92" height="240" alt="" />&nbsp;<img src="http://www.cppblog.com/images/cppblog_com/wang37921/图片24.png" width="92" height="240" alt="" />&nbsp;<img src="http://www.cppblog.com/images/cppblog_com/wang37921/图片25.png" width="40" height="30" alt="" /><br /></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">这次失败后，基本算法将对闭合矩形的高度加一，然后重新放置矩形。但是仅仅加一的话，前四个矩形还是安放在一模一样的位置，最终安放第五个矩形还是失败。这个算法将会继续高度加一继续尝试，可能还是这种情况，周而复始。这些毫无意义的尝试占用了大量的时间。</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">使用下面两个高度中较小的值，来代替高度加一。</span></p><p style="text-indent:20.0000pt; margin-bottom:0pt; margin-top:0pt; "><span style="font-size:10.5000pt; font-family:'Times New Roman'; ">1．</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">无法安放的矩形的高度</span></p><p style="text-indent:20.0000pt; margin-bottom:0pt; margin-top:0pt; "><span style="font-size:10.5000pt; font-family:'Times New Roman'; ">2．</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">可以让闭合矩形对前四个矩形可以进行和之前不同排列的高度&#8212;&#8212;这样至少给算法一个机会来安放第五个矩形</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">通过选择两项中较小的一个，你将可能得到更接近最小的闭合矩形。</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">算出上面第二点中提到的高度并不难，只要你意识到这个算法首先试着在最左列放置每个矩形，如果失败了就查看右边这列再次尝试，直到成功。每次在列中放置矩形失败，那是因为列的底部空闲区域对于矩形来说太矮了&#8212;&#8212;空闲高度不足。</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">拿第二个矩形来说，第一列还差30个像素的空闲高度：</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><img src="http://www.cppblog.com/images/cppblog_com/wang37921/图片26.png" width="60" height="160" alt="" /><br /></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">也就是说，如果闭合矩形再高那么</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">30个像素，第二个矩形就可以放在最左边那列了。</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">同样的，第三个矩形要放在极左列的高度还差25像素，在第二行还差15像素。所以如果闭合矩形再高15个像素，第三个矩形放置的就会不同了：</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><img src="http://www.cppblog.com/images/cppblog_com/wang37921/图片27.png" width="145" height="150" alt="" /><br /></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">第四个矩形在极左列还差</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">10像素的空闲高度。所以如果闭合矩形如果高10个像素，第四个矩形也可能被放置在第一列。</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><img src="http://www.cppblog.com/images/cppblog_com/wang37921/图片28.png" width="75" height="140" alt="" /><br /></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">我们想要增加闭合矩形所需最小的高度使矩形能排的不同即可。这里，最小的所有列所需空闲高度是10个像素（应用于第四个矩形放在极左列）。</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; background:#ff0000; font-family:'宋体'; ">由于第五个矩形高了10个像素放置失败，我们需要将闭合矩形的高度增加10像素，希望在下次尝试时放置第五个矩形：（Seeing&nbsp;that&nbsp;the&nbsp;fifth&nbsp;rectangle&nbsp;that&nbsp;failed&nbsp;to&nbsp;be&nbsp;placed&nbsp;is&nbsp;higher&nbsp;than&nbsp;10px,&nbsp;we&nbsp;need&nbsp;to&nbsp;increase&nbsp;the&nbsp;height&nbsp;of&nbsp;the&nbsp;enclosing&nbsp;rectangle&nbsp;by&nbsp;10px&nbsp;to&nbsp;have&nbsp;any&nbsp;hope&nbsp;of&nbsp;placing&nbsp;the&nbsp;fifth&nbsp;rectangle&nbsp;at&nbsp;the&nbsp;next&nbsp;try:&nbsp;）</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">1				2			3			4				5</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><img src="http://www.cppblog.com/images/cppblog_com/wang37921/图片29.png" width="86" height="260" alt="" />&nbsp;<img src="http://www.cppblog.com/images/cppblog_com/wang37921/图片30.png" width="86" height="260" alt="" />&nbsp;<img src="http://www.cppblog.com/images/cppblog_com/wang37921/图片31.png" width="86" height="260" alt="" />&nbsp;<img src="http://www.cppblog.com/images/cppblog_com/wang37921/图片32.png" width="86" height="260" alt="" />&nbsp;<img src="http://www.cppblog.com/images/cppblog_com/wang37921/图片33.png" width="86" height="260" alt="" /><br /></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">这意味着为了防止那么多的失败闭合矩形，算法需要简单的记录下来在列中放置矩形时最小的空闲高度差额。当放置矩形失败的时候，可以用这个最小空闲高度差额增加闭合矩形的高度&#8212;&#8212;如果无法放置矩形的高度更小的话就用他。</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">这种优化不能确保下一次尝试就能得到成功的闭合矩形。比如，新的高度下，闭合矩形可能会比目前的最佳闭合矩形要打，这种情况下算法将要开始减小他的宽度。这样的话可能会在下次尝试时无法安置所有的矩形因为降低了宽度。此优化是为了减少尝试的次数而非一次成功。</span></p><h3><span style="font-size: 16pt; font-family: 宋体;">闭合矩形大小和速度间的取舍</span></h3><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">如果你决定你可以忍受一定水平的空间浪费，一种方法是减少计算时间来产生闭合矩形，就是当达到这个水平时让代码停止继续获得更小的闭合矩形。</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">另一种方法提高速度是当找到预设次数成功闭合矩形后就让算法停止。你可以设置限制为一次或两次。这很有吸引力，当你发现这种方法可以让你得到一个足够好的结果并且提高了不少速度。</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">为了让你自己选，在MapperOptimalEfficiency类中提供了第二个构造函数，</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; background:#ffff00; font-family:'宋体'; ">通过额外的参数设置这两个选项（with&nbsp;additional&nbsp;parameters&nbsp;to&nbsp;set&nbsp;these&nbsp;two&nbsp;cut&nbsp;offs&nbsp;）</span><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">。</span></p><h2><span style="font-size: 16pt; font-family: 黑体;">矩形打包器的软件接口</span></h2><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">下载Mapper项目中有文章中描述的矩形打包器的实现。他给外部提供了一个良好的接口。test&nbsp;side使用了这个接口。为了让你更容易的学习或者在你的项目使用这些代码，下面提供了接口的描述。</span></p><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">你会发现代码涉及到的是图片和精灵而不是矩形和封闭矩形。这是因为他是打算作为实时精灵生成器项目（还未完成）的一部分实现的。</span></p><h3><span style="font-size: 16pt; font-family: 宋体;">接口</span></h3><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">（译者注：略）</span></p><h3><span style="font-size: 16pt; font-family: 宋体;">实现</span></h3><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">（译者注：略）</span></p><h3><span style="font-size: 16pt; font-family: 宋体;">用法</span></h3><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">（译者注：略）</span></p><h2><span style="font-size: 16pt; font-family: 黑体;">历史记录</span></h2><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">（译者注：略）</span></p><h2><span style="font-size: 16pt; font-family: 黑体;">许可</span></h2><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">（译者注：略）</span></p><h2><span style="font-size: 16pt; font-family: 黑体;">关于作者</span></h2><p style="margin-bottom:0pt; margin-top:0pt; "><span style="mso-spacerun:'yes'; font-size:10.5000pt; font-family:'宋体'; ">（译者注：略）</span></p><p style="margin-bottom:0pt; margin-top:0pt; ">&nbsp;</p><p style="margin-bottom:0pt; margin-top:0pt; ">&nbsp;</p><p style="margin-bottom:0pt; margin-top:0pt; ">&nbsp;</p><img src ="http://www.cppblog.com/wang37921/aggbug/208669.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/wang37921/" target="_blank">王聪</a> 2014-10-24 18:11 <a href="http://www.cppblog.com/wang37921/archive/2014/10/24/208669.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>