问题描述
我正在使用 Binary-Tree-2D-Packing 这个算法在容器中打包矩形。它工作正常,但如果它不适合根节点的右侧,我想旋转该节点。它应该在正确的节点上尝试宽度和高度,如果它不合适,它应该旋转它并使宽度 = 高度和高度 = 宽度然后再试一次。我怎样才能做到这一点?
public class Packer
{
public Packer()
{
Boxes = new List<Box>();
}
public class Node
{
public Node right;
public Node down;
public double x;
public double y;
public double w;
public double h;
public bool used;
}
public class Box
{
public double height;
public double width;
public double area;
public Node position;
}
public List<Box> Boxes;
private Node rootNode;
public void AddBox(Box Box)
{
Box.area = Box.width * Box.height;
Boxes.Add(Box);
}
public void Pack(double containerWidth,double containerHeight)
{
Boxes = Boxes.OrderByDescending(x => x.area).ToList();
rootNode = new Node { w = containerWidth,h = containerHeight };
foreach (var Box in Boxes)
{
var node = FindNode(rootNode,Box.width,Box.height);
if (node != null)
{
Box.position = SplitNode(node,Box.height);
}
else
{
Box.position = GrowNode(Box.width,Box.height);
}
}
}
private Node FindNode(Node rootNode,double w,double h)
{
if (rootNode.used)
{
var nextNode = FindNode(rootNode.right,w,h);
if (nextNode == null)
{
nextNode = FindNode(rootNode.down,h);
}
return nextNode;
}
else if (w <= rootNode.w && h <= rootNode.h)
{
return rootNode;
}
else
{
return null;
}
}
private Node SplitNode(Node node,double h)
{
node.used = true;
node.down = new Node { x = node.x,y = node.y + h,w = node.w,h = node.h - h };
node.right = new Node { x = node.x + w,y = node.y,w = node.w - w,h = h };
return node;
}
private Node GrowNode(double w,double h)
{
bool cangrowDown = (w <= rootNode.w);
bool cangrowRight = (h <= rootNode.h);
bool shouldGrowRight = cangrowRight && (rootNode.h >= (rootNode.w + w));
bool shouldGrowDown = cangrowDown && (rootNode.w >= (rootNode.h + h));
if (shouldGrowRight)
{
return growRight(w,h);
}
else if (shouldGrowDown)
{
return growDown(w,h);
}
else if (cangrowRight)
{
return growRight(w,h);
}
else if (cangrowDown)
{
return growDown(w,h);
}
else
{
return null;
}
}
private Node growRight(double w,double h)
{
rootNode = new Node()
{
used = true,x = 0,y = 0,w = rootNode.w + w,h = rootNode.h,down = rootNode,right = new Node() { x = rootNode.w,w = w,h = rootNode.h }
};
Node node = FindNode(rootNode,h);
if (node != null)
{
return SplitNode(node,h);
}
else
{
return null;
}
}
private Node growDown(double w,w = rootNode.w,h = rootNode.h + h,down = new Node() { x = 0,y = rootNode.h,h = h },right = rootNode
};
Node node = FindNode(rootNode,h);
}
else
{
return null;
}
}
}
解决方法
我将旋转变量添加到 Node
public class Node
{
public Node right;
public Node down;
public double x;
public double y;
public double w;
public double h;
public bool used;
public bool rotated;
}
并在 FindNode
方法中添加了旋转条件
private Node FindNode(Node rootNode,double w,double h)
{
if (rootNode.used)
{
var nextNode = FindNode(rootNode.right,w,h);
if (nextNode == null)
{
nextNode = FindNode(rootNode.right,h,w);
if (nextNode!=null) { nextNode.rotated = true; }
if (nextNode == null)
{
nextNode = FindNode(rootNode.down,h);
}
}
return nextNode;
}
else if (w <= rootNode.w && h <= rootNode.h)
{
return rootNode;
}
else
{
return null;
}
}
最后检查旋转变量是否为真,
public void Pack(double containerWidth,double containerHeight)
{
boxes = boxes.OrderByDescending(x => x.area).ToList();
rootNode = new Node { w = containerWidth,h = containerHeight };
foreach (var box in boxes)
{
var node = FindNode(rootNode,box.width,box.height);
if (node != null)
{
if (node.rotated)
{
double tmp = 0;
tmp = box.width;
box.width = box.height;
box.height = tmp;
}
}
if (node != null)
{
box.position = SplitNode(node,box.height);
}
else
{
box.position = GrowNode(box.width,box.height);
}
}
}
,
除非我误解了某些东西,否则它不会只是两个测试而不是一个吗?即
var node = FindNode(rootNode,box.height);
if (node != null)
{
box.position = SplitNode(node,box.height);
}
else
{
node = FindNode(rootNode,box.height,box.width);
if(node!= null){
box.position = SplitNode(node,box.width);
}
box.position = GrowNode(box.width,box.height);
}
请注意,GrowNode
将始终按宽高顺序增长。
如果树是不可变的,您也可以尝试每个替代方案并比较结果节点。:
Node whNode,hwNode;
var node = FindNode(rootNode,box.height);
if (node != null)
{
whNode = SplitNode(node,box.height);
}
else
{
whNode = GrowNode(box.width,box.height);
}
node = FindNode(rootNode,box.width);
if (node != null)
{
hwNode= SplitNode(node,box.width);
}
else
{
hwNode= GrowNode(box.height,box.width);
}
box.Position = GetBestNode(whNode,hwNode);