C#二叉树二维打包算法旋转
C# Binary Tree 2D Packing Algorithm Rotation
我正在使用 Binary-Tree-2D-Packing 这个算法在容器中打包矩形。它工作正常,但如果节点不适合根节点,我想旋转该节点。它应该在正确的节点尝试宽度和高度,如果它不合适,它应该旋转它并使 width = height 和 height = width 然后再试一次。我怎样才能做到这一点?
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.width, 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, w, h);
}
return nextNode;
}
else if (w <= rootNode.w && h <= rootNode.h)
{
return rootNode;
}
else
{
return null;
}
}
private Node SplitNode(Node node, double w, 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, y = 0, w = w, h = rootNode.h }
};
Node node = FindNode(rootNode, w, h);
if (node != null)
{
return SplitNode(node, w, h);
}
else
{
return null;
}
}
private Node growDown(double w, double h)
{
rootNode = new Node()
{
used = true,
x = 0,
y = 0,
w = rootNode.w,
h = rootNode.h + h,
down = new Node() { x = 0, y = rootNode.h, w = rootNode.w, h = h },
right = rootNode
};
Node node = FindNode(rootNode, w, h);
if (node != null)
{
return SplitNode(node, w, h);
}
else
{
return null;
}
}
}
除非我误会了什么,否则它不会只是两个测试而不是一个吗?即
var node = FindNode(rootNode, box.width, box.height);
if (node != null)
{
box.position = SplitNode(node, box.width, box.height);
}
else
{
node = FindNode(rootNode, box.height, box.width);
if(node!= null){
box.position = SplitNode(node, box.height, box.width);
}
box.position = GrowNode(box.width, box.height);
}
请注意 GrowNode
总是按宽高顺序增长。
如果树是不可变的,您也可以尝试每个替代方案并比较结果节点。:
Node whNode, hwNode;
var node = FindNode(rootNode, box.width, box.height);
if (node != null)
{
whNode = SplitNode(node, box.width, box.height);
}
else
{
whNode = GrowNode(box.width, box.height);
}
node = FindNode(rootNode, box.height, box.width);
if (node != null)
{
hwNode= SplitNode(node, box.height, box.width);
}
else
{
hwNode= GrowNode(box.height, box.width);
}
box.Position = GetBestNode(whNode, hwNode);
我将旋转变量添加到 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, w, 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.width, box.height);
}
else
{
box.position = GrowNode(box.width, box.height);
}
}
}
我正在使用 Binary-Tree-2D-Packing 这个算法在容器中打包矩形。它工作正常,但如果节点不适合根节点,我想旋转该节点。它应该在正确的节点尝试宽度和高度,如果它不合适,它应该旋转它并使 width = height 和 height = width 然后再试一次。我怎样才能做到这一点?
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.width, 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, w, h);
}
return nextNode;
}
else if (w <= rootNode.w && h <= rootNode.h)
{
return rootNode;
}
else
{
return null;
}
}
private Node SplitNode(Node node, double w, 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, y = 0, w = w, h = rootNode.h }
};
Node node = FindNode(rootNode, w, h);
if (node != null)
{
return SplitNode(node, w, h);
}
else
{
return null;
}
}
private Node growDown(double w, double h)
{
rootNode = new Node()
{
used = true,
x = 0,
y = 0,
w = rootNode.w,
h = rootNode.h + h,
down = new Node() { x = 0, y = rootNode.h, w = rootNode.w, h = h },
right = rootNode
};
Node node = FindNode(rootNode, w, h);
if (node != null)
{
return SplitNode(node, w, h);
}
else
{
return null;
}
}
}
除非我误会了什么,否则它不会只是两个测试而不是一个吗?即
var node = FindNode(rootNode, box.width, box.height);
if (node != null)
{
box.position = SplitNode(node, box.width, box.height);
}
else
{
node = FindNode(rootNode, box.height, box.width);
if(node!= null){
box.position = SplitNode(node, box.height, box.width);
}
box.position = GrowNode(box.width, box.height);
}
请注意 GrowNode
总是按宽高顺序增长。
如果树是不可变的,您也可以尝试每个替代方案并比较结果节点。:
Node whNode, hwNode;
var node = FindNode(rootNode, box.width, box.height);
if (node != null)
{
whNode = SplitNode(node, box.width, box.height);
}
else
{
whNode = GrowNode(box.width, box.height);
}
node = FindNode(rootNode, box.height, box.width);
if (node != null)
{
hwNode= SplitNode(node, box.height, box.width);
}
else
{
hwNode= GrowNode(box.height, box.width);
}
box.Position = GetBestNode(whNode, hwNode);
我将旋转变量添加到 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, w, 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.width, box.height);
}
else
{
box.position = GrowNode(box.width, box.height);
}
}
}