新增maxRectsBinPack

This commit is contained in:
yhh
2020-12-24 11:12:24 +08:00
parent fa10d5d4d5
commit 90d84f9316
11 changed files with 340 additions and 6 deletions

View File

@@ -3575,6 +3575,22 @@ declare module es {
tickCoroutine(coroutine: CoroutineImpl): boolean;
}
}
declare module es {
class MaxRectsBinPack {
binWidth: number;
binHeight: number;
allowRotations: boolean;
usedRectangles: Rectangle[];
freeRectangles: Rectangle[];
constructor(width: number, height: number, rotations?: boolean);
init(width: number, height: number, rotations?: boolean): void;
insert(width: number, height: number): Rectangle;
findPositionForNewNodeBestAreaFit(width: number, height: number, bestAreaFit: Ref<number>, bestShortSideFit: Ref<number>): Rectangle;
splitFreeNode(freeNode: Rectangle, usedNode: Rectangle): boolean;
pruneFreeList(): void;
isContainedIn(a: Rectangle, b: Rectangle): boolean;
}
}
declare class ArrayUtils {
/**
* 执行冒泡排序

View File

@@ -8995,6 +8995,145 @@ var es;
}(es.GlobalManager));
es.CoroutineManager = CoroutineManager;
})(es || (es = {}));
var es;
(function (es) {
var MaxRectsBinPack = /** @class */ (function () {
function MaxRectsBinPack(width, height, rotations) {
if (rotations === void 0) { rotations = true; }
this.binWidth = 0;
this.binHeight = 0;
this.usedRectangles = [];
this.freeRectangles = [];
this.init(width, height, rotations);
}
MaxRectsBinPack.prototype.init = function (width, height, rotations) {
if (rotations === void 0) { rotations = true; }
this.binWidth = width;
this.binHeight = height;
this.allowRotations = rotations;
var n = new es.Rectangle();
n.x = 0;
n.y = 0;
n.width = width;
n.height = height;
this.usedRectangles.length = 0;
this.freeRectangles.length = 0;
this.freeRectangles.push(n);
};
MaxRectsBinPack.prototype.insert = function (width, height) {
var newNode = new es.Rectangle();
var score1 = new es.Ref(0);
var score2 = new es.Ref(0);
newNode = this.findPositionForNewNodeBestAreaFit(width, height, score1, score2);
if (newNode.height == 0)
return newNode;
var numRectanglesToProcess = this.freeRectangles.length;
for (var i = 0; i < numRectanglesToProcess; ++i) {
if (this.splitFreeNode(this.freeRectangles[i], newNode)) {
new linq.List(this.freeRectangles).removeAt(i);
--i;
--numRectanglesToProcess;
}
}
this.pruneFreeList();
this.usedRectangles.push(newNode);
return newNode;
};
MaxRectsBinPack.prototype.findPositionForNewNodeBestAreaFit = function (width, height, bestAreaFit, bestShortSideFit) {
var bestNode = new es.Rectangle();
bestAreaFit.value = Number.MAX_VALUE;
for (var i = 0; i < this.freeRectangles.length; ++i) {
var areaFit = this.freeRectangles[i].width * this.freeRectangles[i].height - width * height;
// 试着将长方形放在直立(非翻转)的方向
if (this.freeRectangles[i].width >= width && this.freeRectangles[i].height >= height) {
var leftoverHoriz = Math.abs(this.freeRectangles[i].width - width);
var leftoverVert = Math.abs(this.freeRectangles[i].height - height);
var shortSideFit = Math.min(leftoverHoriz, leftoverVert);
if (areaFit < bestAreaFit.value || (areaFit == bestAreaFit.value && shortSideFit < bestShortSideFit.value)) {
bestNode.x = this.freeRectangles[i].x;
bestNode.y = this.freeRectangles[i].y;
bestNode.width = width;
bestNode.height = height;
bestShortSideFit.value = shortSideFit;
bestAreaFit.value = areaFit;
}
}
if (this.allowRotations && this.freeRectangles[i].width >= height && this.freeRectangles[i].height >= width) {
var leftoverHoriz = Math.abs(this.freeRectangles[i].width - height);
var leftoverVert = Math.abs(this.freeRectangles[i].height - width);
var shortSideFit = Math.min(leftoverHoriz, leftoverVert);
if (areaFit < bestAreaFit.value || (areaFit == bestAreaFit.value && shortSideFit < bestShortSideFit.value)) {
bestNode.x = this.freeRectangles[i].x;
bestNode.y = this.freeRectangles[i].y;
bestNode.width = height;
bestNode.height = width;
bestShortSideFit.value = shortSideFit;
bestAreaFit.value = areaFit;
}
}
return bestNode;
}
};
MaxRectsBinPack.prototype.splitFreeNode = function (freeNode, usedNode) {
// 用SAT测试长方形是否均匀相交
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;
if (usedNode.x < freeNode.x + freeNode.width && usedNode.x + usedNode.width > freeNode.x) {
// 在使用过的节点的上边新建一个节点
if (usedNode.y > freeNode.y && usedNode.y < freeNode.y + freeNode.height) {
var newNode = freeNode;
newNode.height = usedNode.y - newNode.y;
this.freeRectangles.push(newNode);
}
// 在使用过的节点的底边新建节点
if (usedNode.y + usedNode.height < freeNode.y + freeNode.height) {
var newNode = freeNode;
newNode.y = usedNode.y + usedNode.height;
newNode.height = freeNode.y + freeNode.height - (usedNode.y + usedNode.height);
this.freeRectangles.push(newNode);
}
}
if (usedNode.y < freeNode.y + freeNode.height && usedNode.y + usedNode.height > freeNode.y) {
// 在使用过的节点的左侧新建节点
if (usedNode.x > freeNode.x && usedNode.x < freeNode.x + freeNode.width) {
var newNode = freeNode;
newNode.width = usedNode.x - newNode.x;
this.freeRectangles.push(newNode);
}
// 在使用过的节点右侧新建节点
if (usedNode.x + usedNode.width < freeNode.x + freeNode.width) {
var newNode = freeNode;
newNode.x = usedNode.x + usedNode.width;
newNode.width = freeNode.x + freeNode.width - (usedNode.x + usedNode.width);
this.freeRectangles.push(newNode);
}
}
return true;
};
MaxRectsBinPack.prototype.pruneFreeList = function () {
for (var i = 0; i < this.freeRectangles.length; ++i)
for (var j = i + 1; j < this.freeRectangles.length; ++j) {
if (this.isContainedIn(this.freeRectangles[i], this.freeRectangles[j])) {
new linq.List(this.freeRectangles).removeAt(i);
--i;
break;
}
if (this.isContainedIn(this.freeRectangles[j], this.freeRectangles[i])) {
new linq.List(this.freeRectangles).removeAt(j);
--j;
}
}
};
MaxRectsBinPack.prototype.isContainedIn = function (a, b) {
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;
};
return MaxRectsBinPack;
}());
es.MaxRectsBinPack = MaxRectsBinPack;
})(es || (es = {}));
var ArrayUtils = /** @class */ (function () {
function ArrayUtils() {
}

File diff suppressed because one or more lines are too long