来自:http://www.duzengqiang.com/blog/post/971.html 转载请标明出处。

What's MaxRectsBinPack

MaxRects算法是一个二维图像排列算法,在FlashCS6的Sprite导出功能和TexturePacker中均有使用.

Reference

Based on the Public Domain MaxRectanglesBinPack.cpp source by Jukka Jylänki
https://github.com/juj/RectangleBinPack/

Based on C# port by Sven Magnus
http://unifycommunity.com/wiki/index.php?title=MaxRectanglesBinPack

Ported to ActionScript3 by DUZENGQIANG
This version is also public domain - do whatever you want with it.

Source Code

/*
Based on the Public Domain MaxRectanglesBinPack.cpp source by Jukka Jyl?nki
https://github.com/juj/RectangleBinPack/Based on C# port by Sven Magnus
http://unifycommunity.com/wiki/index.php?title=MaxRectanglesBinPackPorted to ActionScript3 by DUZENGQIANG
http://www.duzengqiang.com/blog/post/971.html
This version is also public domain - do whatever you want with it.
*/package
{
import flash.display.*;
import flash.events.*;
import flash.geom.Rectangle;
import flash.net.*;/***  MaxRectanglesBinPack*  @author DUZENGQIANG*  @date Jun 7, 2012*  @version 1.0*  <p>SinaMicroBlog: http://weibo.com/duzengqiang</p>*  <p>blog: http://www.duzengqiang.com</p>*/
public class MaxRectsBinPack
{      public var binWidth:int = 0;public var binHeight:int = 0;public var allowRotations:Boolean = false;public var usedRectangles:Vector.<Rectangle> = new Vector.<Rectangle>();public var freeRectangles:Vector.<Rectangle> = new Vector.<Rectangle>();private var score1:int = 0; // Unused in this function. We don't need to know the score after finding the position.private var score2:int = 0;private var bestShortSideFit:int;private var bestLongSideFit:int;public function MaxRectsBinPack( width:int, height:int, rotations:Boolean = true) {init(width, height, rotations);}private function init(width:int, height:int, rotations:Boolean = true):void{if( count(width) % 1 != 0 ||count(height) % 1 != 0)throw new Error("Must be 2,4,8,16,32,...512,1024,...");binWidth = width;binHeight = height;allowRotations = rotations;var n:Rectangle = new Rectangle();n.x = 0;n.y = 0;n.width = width;n.height = height;usedRectangles.length = 0;freeRectangles.length = 0;freeRectangles.push( n );}private function count(n:Number):Number{if( n >= 2 )return count(n / 2);return n;}/*** Insert a new Rectangle * @param width* @param height* @param method* @return * */     public function insert(width:int, height:int,  method:int):Rectangle {var newNode:Rectangle  = new Rectangle();score1 = 0;score2 = 0;switch(method) {case FreeRectangleChoiceHeuristic.BestShortSideFit: newNode = findPositionForNewNodeBestShortSideFit(width, height); break;case FreeRectangleChoiceHeuristic.BottomLeftRule: newNode = findPositionForNewNodeBottomLeft(width, height, score1, score2); break;case FreeRectangleChoiceHeuristic.ContactPointRule: newNode = findPositionForNewNodeContactPoint(width, height, score1); break;case FreeRectangleChoiceHeuristic.BestLongSideFit: newNode = findPositionForNewNodeBestLongSideFit(width, height, score2, score1); break;case FreeRectangleChoiceHeuristic.BestAreaFit: newNode = findPositionForNewNodeBestAreaFit(width, height, score1, score2); break;}if (newNode.height == 0)return newNode;placeRectangle(newNode);trace(newNode);return newNode;}private function insert2( Rectangles:Vector.<Rectangle>, dst:Vector.<Rectangle>, method:int):void {dst.length = 0;while(Rectangles.length > 0) {var bestScore1:int = int.MAX_VALUE;var bestScore2:int = int.MAX_VALUE;var bestRectangleIndex:int = -1;var bestNode:Rectangle = new Rectangle();for(var i:int = 0; i < Rectangles.length; ++i) {var score1:int = 0;var score2:int = 0;var newNode:Rectangle = scoreRectangle(Rectangles[i].width, Rectangles[i].height, method, score1, score2);if (score1 < bestScore1 || (score1 == bestScore1 && score2 < bestScore2)) {bestScore1 = score1;bestScore2 = score2;bestNode = newNode;bestRectangleIndex = i;}}if (bestRectangleIndex == -1)return;placeRectangle(bestNode);Rectangles.splice(bestRectangleIndex,1);}}private function placeRectangle(node:Rectangle):void {var numRectanglesToProcess:int = freeRectangles.length;for(var i:int = 0; i < numRectanglesToProcess; i++) {if (splitFreeNode(freeRectangles[i], node)) {freeRectangles.splice(i,1);--i;--numRectanglesToProcess;}}pruneFreeList();usedRectangles.push(node);}private function scoreRectangle( width:int,  height:int,  method:int, score1:int, score2:int):Rectangle {var newNode:Rectangle = new Rectangle();score1 = int.MAX_VALUE;score2 = int.MAX_VALUE;switch(method) {case FreeRectangleChoiceHeuristic.BestShortSideFit: newNode = findPositionForNewNodeBestShortSideFit(width, height); break;case FreeRectangleChoiceHeuristic.BottomLeftRule: newNode = findPositionForNewNodeBottomLeft(width, height, score1,score2); break;case FreeRectangleChoiceHeuristic.ContactPointRule: newNode = findPositionForNewNodeContactPoint(width, height, score1); // todo: reversescore1 = -score1; // Reverse since we are minimizing, but for contact point score bigger is better.break;case FreeRectangleChoiceHeuristic.BestLongSideFit: newNode = findPositionForNewNodeBestLongSideFit(width, height, score2, score1); break;case FreeRectangleChoiceHeuristic.BestAreaFit: newNode = findPositionForNewNodeBestAreaFit(width, height, score1, score2); break;}// Cannot fit the current Rectangle.if (newNode.height == 0) {score1 = int.MAX_VALUE;score2 = int.MAX_VALUE;}return newNode;}/// Computes the ratio of used surface area.private function occupancy():Number {var usedSurfaceArea:Number = 0;for(var i:int = 0; i < usedRectangles.length; i++)usedSurfaceArea += usedRectangles[i].width * usedRectangles[i].height;return usedSurfaceArea / (binWidth * binHeight);}private function findPositionForNewNodeBottomLeft(width:int, height:int, bestY:int, bestX:int) {var bestNode:Rectangle = new Rectangle();//memset(bestNode, 0, sizeof(Rectangle));bestY = int.MAX_VALUE;var rect:Rectangle;var topSideY:int;for(var i:int = 0; i < freeRectangles.length; i++) {rect = freeRectangles[i];// Try to place the Rectangle in upright (non-flipped) orientation.if (rect.width >= width && rect.height >= height) {topSideY = rect.y + height;if (topSideY < bestY || (topSideY == bestY && rect.x < bestX)) {bestNode.x = rect.x;bestNode.y = rect.y;bestNode.width = width;bestNode.height = height;bestY = topSideY;bestX = rect.x;}}if (allowRotations && rect.width >= height && rect.height >= width) {topSideY = rect.y + width;if (topSideY < bestY || (topSideY == bestY && rect.x < bestX)) {bestNode.x = rect.x;bestNode.y = rect.y;bestNode.width = height;bestNode.height = width;bestY = topSideY;bestX = rect.x;}}}return bestNode;}private function findPositionForNewNodeBestShortSideFit(width:int, height:int):Rectangle  {var bestNode:Rectangle = new Rectangle();//memset(&bestNode, 0, sizeof(Rectangle));bestShortSideFit = int.MAX_VALUE;bestLongSideFit = score2;var rect:Rectangle;var leftoverHoriz:int;var leftoverVert:int;var shortSideFit:int;var longSideFit:int;for(var i:int = 0; i < freeRectangles.length; i++) {rect = freeRectangles[i];// Try to place the Rectangle in upright (non-flipped) orientation.if (rect.width >= width && rect.height >= height) {leftoverHoriz = Math.abs(rect.width - width);leftoverVert = Math.abs(rect.height - height);shortSideFit = Math.min(leftoverHoriz, leftoverVert);longSideFit = Math.max(leftoverHoriz, leftoverVert);if (shortSideFit < bestShortSideFit || (shortSideFit == bestShortSideFit && longSideFit < bestLongSideFit)) {bestNode.x = rect.x;bestNode.y = rect.y;bestNode.width = width;bestNode.height = height;bestShortSideFit = shortSideFit;bestLongSideFit = longSideFit;}}var flippedLeftoverHoriz:int;var flippedLeftoverVert:int;var flippedShortSideFit:int;var flippedLongSideFit:int;if (allowRotations && rect.width >= height && rect.height >= width) {var flippedLeftoverHoriz = Math.abs(rect.width - height);var flippedLeftoverVert = Math.abs(rect.height - width);var flippedShortSideFit = Math.min(flippedLeftoverHoriz, flippedLeftoverVert);var flippedLongSideFit = Math.max(flippedLeftoverHoriz, flippedLeftoverVert);if (flippedShortSideFit < bestShortSideFit || (flippedShortSideFit == bestShortSideFit && flippedLongSideFit < bestLongSideFit)) {bestNode.x = rect.x;bestNode.y = rect.y;bestNode.width = height;bestNode.height = width;bestShortSideFit = flippedShortSideFit;bestLongSideFit = flippedLongSideFit;}}}return bestNode;}private function  findPositionForNewNodeBestLongSideFit(width:int, height:int, bestShortSideFit:int, bestLongSideFit:int):Rectangle {var bestNode:Rectangle = new Rectangle();//memset(&bestNode, 0, sizeof(Rectangle));bestLongSideFit = int.MAX_VALUE;var rect:Rectangle;var leftoverHoriz:int;var leftoverVert:int;var shortSideFit:int;var longSideFit:int;for(var i:int = 0; i < freeRectangles.length; i++) {rect = freeRectangles[i];// Try to place the Rectangle in upright (non-flipped) orientation.if (rect.width >= width && rect.height >= height) {leftoverHoriz = Math.abs(rect.width - width);leftoverVert = Math.abs(rect.height - height);shortSideFit = Math.min(leftoverHoriz, leftoverVert);longSideFit = Math.max(leftoverHoriz, leftoverVert);if (longSideFit < bestLongSideFit || (longSideFit == bestLongSideFit && shortSideFit < bestShortSideFit)) {bestNode.x = rect.x;bestNode.y = rect.y;bestNode.width = width;bestNode.height = height;bestShortSideFit = shortSideFit;bestLongSideFit = longSideFit;}}if (allowRotations && rect.width >= height && rect.height >= width) {leftoverHoriz = Math.abs(rect.width - height);leftoverVert = Math.abs(rect.height - width);shortSideFit = Math.min(leftoverHoriz, leftoverVert);longSideFit = Math.max(leftoverHoriz, leftoverVert);if (longSideFit < bestLongSideFit || (longSideFit == bestLongSideFit && shortSideFit < bestShortSideFit)) {bestNode.x = rect.x;bestNode.y = rect.y;bestNode.width = height;bestNode.height = width;bestShortSideFit = shortSideFit;bestLongSideFit = longSideFit;}}}trace(bestNode);return bestNode;}private function findPositionForNewNodeBestAreaFit(width:int, height:int, bestAreaFit:int, bestShortSideFit:int):Rectangle {var bestNode:Rectangle = new Rectangle();//memset(&bestNode, 0, sizeof(Rectangle));bestAreaFit = int.MAX_VALUE;var rect:Rectangle;var leftoverHoriz:int;var leftoverVert:int;var shortSideFit:int;var areaFit:int;for(var i:int = 0; i < freeRectangles.length; i++) {rect = freeRectangles[i];areaFit = rect.width * rect.height - width * height;// Try to place the Rectangle in upright (non-flipped) orientation.if (rect.width >= width && rect.height >= height) {leftoverHoriz = Math.abs(rect.width - width);leftoverVert = Math.abs(rect.height - height);shortSideFit = Math.min(leftoverHoriz, leftoverVert);if (areaFit < bestAreaFit || (areaFit == bestAreaFit && shortSideFit < bestShortSideFit)) {bestNode.x = rect.x;bestNode.y = rect.y;bestNode.width = width;bestNode.height = height;bestShortSideFit = shortSideFit;bestAreaFit = areaFit;}}if (allowRotations && rect.width >= height && rect.height >= width) {leftoverHoriz = Math.abs(rect.width - height);leftoverVert = Math.abs(rect.height - width);shortSideFit = Math.min(leftoverHoriz, leftoverVert);if (areaFit < bestAreaFit || (areaFit == bestAreaFit && shortSideFit < bestShortSideFit)) {bestNode.x = rect.x;bestNode.y = rect.y;bestNode.width = height;bestNode.height = width;bestShortSideFit = shortSideFit;bestAreaFit = areaFit;}}}return bestNode;}/// Returns 0 if the two intervals i1 and i2 are disjoint, or the length of their overlap otherwise.private function commonIntervalLength(i1start:int, i1end:int, i2start:int, i2end:int):int {if (i1end < i2start || i2end < i1start)return 0;return Math.min(i1end, i2end) - Math.max(i1start, i2start);}private function contactPointScoreNode(x:int, y:int, width:int, height:int):int {var score:int = 0;if (x == 0 || x + width == binWidth)score += height;if (y == 0 || y + height == binHeight)score += width;var rect:Rectangle;for(var i:int = 0; i < usedRectangles.length; i++) {rect = usedRectangles[i];if (rect.x == x + width || rect.x + rect.width == x)score += commonIntervalLength(rect.y, rect.y + rect.height, y, y + height);if (rect.y == y + height || rect.y + rect.height == y)score += commonIntervalLength(rect.x, rect.x + rect.width, x, x + width);}return score;}private function findPositionForNewNodeContactPoint(width:int, height:int, bestContactScore:int):Rectangle {var bestNode:Rectangle = new Rectangle();//memset(&bestNode, 0, sizeof(Rectangle));bestContactScore = -1;var rect:Rectangle;var score:int;for(var i:int = 0; i < freeRectangles.length; i++) {rect = freeRectangles[i];// Try to place the Rectangle in upright (non-flipped) orientation.if (rect.width >= width && rect.height >= height) {score = contactPointScoreNode(rect.x, rect.y, width, height);if (score > bestContactScore) {bestNode.x = rect.x;bestNode.y = rect.y;bestNode.width = width;bestNode.height = height;bestContactScore = score;}}if (allowRotations && rect.width >= height && rect.height >= width) {score = contactPointScoreNode(rect.x, rect.y, height, width);if (score > bestContactScore) {bestNode.x = rect.x;bestNode.y = rect.y;bestNode.width = height;bestNode.height = width;bestContactScore = score;}}}return bestNode;}private function splitFreeNode(freeNode:Rectangle, usedNode:Rectangle):Boolean {// Test with SAT if the Rectangles even intersect.if (usedNode.x >= freeNode.x + freeNode.width || usedNode.x + usedNode.width <= freeNode.x ||usedNode.y >= freeNode.y + freeNode.height || usedNode.y + usedNode.height <= freeNode.y)return false;var newNode:Rectangle;if (usedNode.x < freeNode.x + freeNode.width && usedNode.x + usedNode.width > freeNode.x) {// New node at the top side of the used node.if (usedNode.y > freeNode.y && usedNode.y < freeNode.y + freeNode.height) {newNode = freeNode.clone();newNode.height = usedNode.y - newNode.y;freeRectangles.push(newNode);}// New node at the bottom side of the used node.if (usedNode.y + usedNode.height < freeNode.y + freeNode.height) {newNode = freeNode.clone();newNode.y = usedNode.y + usedNode.height;newNode.height = freeNode.y + freeNode.height - (usedNode.y + usedNode.height);freeRectangles.push(newNode);}}if (usedNode.y < freeNode.y + freeNode.height && usedNode.y + usedNode.height > freeNode.y) {// New node at the left side of the used node.if (usedNode.x > freeNode.x && usedNode.x < freeNode.x + freeNode.width) {newNode = freeNode.clone();newNode.width = usedNode.x - newNode.x;freeRectangles.push(newNode);}// New node at the right side of the used node.if (usedNode.x + usedNode.width < freeNode.x + freeNode.width) {newNode = freeNode.clone();newNode.x = usedNode.x + usedNode.width;newNode.width = freeNode.x + freeNode.width - (usedNode.x + usedNode.width);freeRectangles.push(newNode);}}return true;}private function pruneFreeList():void {for(var i:int = 0; i < freeRectangles.length; i++)for(var j:int = i+1; j < freeRectangles.length; j++) {if (isContainedIn(freeRectangles[i], freeRectangles[j])) {freeRectangles.splice(i,1);break;}if (isContainedIn(freeRectangles[j], freeRectangles[i])) {freeRectangles.splice(j,1);}}}private function isContainedIn(a:Rectangle, b:Rectangle):Boolean {return a.x >= b.x && a.y >= b.y && a.x+a.width <= b.x+b.width && a.y+a.height <= b.y+b.height;}}}class FreeRectangleChoiceHeuristic {public static const BestShortSideFit:int = 0; ///< -BSSF: Positions the Rectangle against the short side of a free Rectangle into which it fits the best.public static const BestLongSideFit:int = 1; ///< -BLSF: Positions the Rectangle against the long side of a free Rectangle into which it fits the best.public static const BestAreaFit:int = 2; ///< -BAF: Positions the Rectangle into the smallest free Rectangle into which it fits.public static const BottomLeftRule:int = 3; ///< -BL: Does the Tetris placement.public static const ContactPointRule:int = 4; ///< -CP: Choosest the placement where the Rectangle touches other Rectangles as much as possible.
}

Download

MaxRectsBinPack.as

How to use

//Create new MaxRectsBinPack instance
var maxRect:MaxRectsBinPack = new MaxRectsBinPack(1024,1024,false);
// insert new rectangle
maxRect.insert(300,200,0);

//There are 5 insert method in FreeRectangleChoiceHeuristic class.
// class FreeRectangleChoiceHeuristic {
// public static const BestShortSideFit:int = 0; ///< -BSSF: Positions the Rectangle against the short side of a free Rectangle into which it fits the best.
// public static const BestLongSideFit:int = 1; ///< -BLSF: Positions the Rectangle against the long side of a free Rectangle into which it fits the best.
// public static const BestAreaFit:int = 2; ///< -BAF: Positions the Rectangle into the smallest free Rectangle into which it fits.
// public static const BottomLeftRule:int = 3; ///< -BL: Does the Tetris placement.
// public static const ContactPointRule:int = 4; ///< -CP: Choosest the placement where the Rectangle touches other Rectangles as much as possible.
//}

usedRectangles: storage of all used rectangles
freeRectangles: storage of all free rectangles
The insert method will return a rectangle. when its width an height are both 0. That means it can not be inserted anymore.

For more information, see a series of blog posts at
http://clb.demon.fi/projects/rectangle-bin-packing
http://clb.demon.fi/projects/more-rectangle-bin-packing
http://clb.demon.fi/projects/even-more-rectangle-bin-packing

使用方法:http://www.cnblogs.com/yourihua/archive/2012/06/19/2554687.html

MaxRects纹理合并算法as3实现相关推荐

  1. 图像分割-区域分裂合并算法

    原文:https://www.jianshu.com/p/fa573431ef3d 区域分裂合并法:区域分裂合并法是一种图像分割算法. 它与区域生长法略有相似之处,但无需预先指定种子点,而是按某种一致 ...

  2. python 信息检索,python信息检索代码_信息检索_倒排记录表合并算法实现(python)...

    小程序描述:输入两个倒排记录表,求两个倒排记录表的交集. 倒排记录表合并算法伪代码如下所示: 功能描述: ①运行程序,看到提示"请输入词项word1:",输入某个倒排记录表的词项. ...

  3. 【图像处理】纹理检测算法

    图像纹理检测算法 LBP检测算法 原文链接:https://blog.csdn.net/tiandijun/article/details/45561981 https://blog.csdn.net ...

  4. git 的合并原理(递归三路合并算法)

    如果 git 只是一行行比较,然后把不同的行报成冲突,那么你在合并的时候可能会遇到大量的冲突:这显然不是一个好的版本管理工具. 本文介绍 git 合并分支的原理. 本文内容 git 的冲突表示 三路合 ...

  5. 【Let It Be Color!——3D重建之纹理重建】02-基于映射的纹理重建算法(上)

    文章转自:https://bbs.huaweicloud.com/blogs/195742 原文作者:景末 来自:华为云社区 1 引言 在上一篇博文中,我们已经提到过纹理重建的主流方案可以分成基于融合 ...

  6. 记一次图层合并算法设计

    一张完整的图像可能是由若干个大小不同的图层组成的.如果由计算机将这若干个图层渲染成一张完整的图像,则需要根据图层的z值(也可以理解为远近关系,z值越大,从视觉角度来看,图层被显现的内容越多),所以,一 ...

  7. 图像纹理合成及纹理传输算法学习(附源码)。

    有2到3年没有逛CodeProject了,上班一时无聊,就翻翻这个比较有名的国外网站,在其Articles » Multimedia » General Graphics » Graphics一栏看到 ...

  8. 单链表的合并算法_图解算法:单链表两两反转 | 眼睛会了手就会系列

    一. 序 链表作为一种基本的数据结构,本身理解起来,很简单.它通过指针或者叫引用,将一组零散的内存空间(结点),串联起来组成一个数据存储结构. 链表根据其指针的指向和丰富程度,可以分为单链表.双向链表 ...

  9. java 合并算法思想_Java实现合并两个有序序列算法示例

    本文实例讲述了Java实现合并两个有序序列算法.分享给大家供大家参考,具体如下: 问题描述 输入:序列A,其中a0,其中b0 算法思想 创建一个长度为r的数组R,将A中的序列看作是两个有序序列 B=A ...

最新文章

  1. JavaScript - Closure
  2. android 下滑,Android实现下滑和上滑事件
  3. [MobX State Tree数据组件化开发][3]:选择正确的types.xxx
  4. 将 SharePoint 开发与其他形式的开发进行比较
  5. 【原创】大叔问题定位分享(11)Spark中对大表子查询加limit为什么会报Broadcast超时错误...
  6. 数据结构上机实践第14周项目3 - 是否二叉排序树
  7. lisp 角平分线_《最佳Visual-LISP-及VBA-for-AutoCAD-2000程序123例》.pdf
  8. Proto3 Any与Oneof(转载)
  9. 数据-第8课-线性表的链式存储结构(未)
  10. 到底什么才是自动化巡检?
  11. python一二维数据的格式化和处理_python第七周,二维数据的格式化和处理
  12. 联邦学习后门攻击代码阅读——backdoors101
  13. [OMNET++]ALOHA协议
  14. 【python numpy库的使用】向量的加减法
  15. python一对一辅导教程:Computational Problems for Physics chapter 1-A Code Listings 1.1 - 1.6
  16. 解决PageHelper版本不匹配,结果可能全部返回问题
  17. Array王锐大神力作:osg与PhysX结合系列内容——第5节 角色动画效果(上)
  18. JS实现拼接图片src
  19. maven 多模块项目,打包其中一个项目,Could not find artifact org.javaboy:commons:pom:1.0-SNAPSHOT
  20. python中write什么意思_python file write () 方法概括及作用分析(实例)

热门文章

  1. 思科模拟器叫什么_《班主任模拟器》第155关怎么过 通关技巧分享
  2. 东北林业大学c语言期末考试题,东北林业大学 2008年C语言考试试卷及答案.doc
  3. python如何创建一个列表,在python中创建一个由列表索引的字典
  4. 网络爬虫随记:2018-03-12启(refreshing)
  5. Struts2入门这一篇就够了 1
  6. Node.js 学习笔记(三)
  7. python中关于集合的基础运用
  8. 行转列经典案例(left join)
  9. 解密Angular WebWorker Renderer (二)
  10. thing php官网,Thinkphp5企业官网,php后台管理框架