C#二叉树二维装箱算法旋转
我用这个算法在一个容器中包装矩形。它工作得很好,但如果它不适合根节点的右侧,我想旋转节点。它应该在右侧节点尝试宽度和高度,如果不合适,应该旋转它,使宽度=高度,高度=宽度,然后重试。我怎样才能做到这一点C#二叉树二维装箱算法旋转,c#,bin-packing,C#,Bin Packing,我用这个算法在一个容器中包装矩形。它工作得很好,但如果它不适合根节点的右侧,我想旋转节点。它应该在右侧节点尝试宽度和高度,如果不合适,应该旋转它,使宽度=高度,高度=宽度,然后重试。我怎样才能做到这一点 public class Packer { public Packer() { boxes = new List<Box>(); } public clas
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;
}
}
}
公共类封隔器
{
公共包装商()
{
框=新列表();
}
公共类节点
{
公共节点权;
公共节点关闭;
公共双x;
公共双y;
公共双w;
公共双h;
使用公共厕所;
}
公共类箱
{
公众双高;
公共双宽度;
公共双区;
公共节点位置;
}
公共列表框;
专用节点rootNode;
公共无效地址框(Box)
{
box.area=box.width*box.height;
框。添加(框);
}
公共空包(双集装箱宽度、双集装箱高度)
{
box=box.OrderByDescending(x=>x.area.ToList();
rootNode=newnode{w=containerWidth,h=containerHeight};
foreach(框中的变量框)
{
var node=FindNode(rootNode,box.width,box.height);
如果(节点!=null)
{
box.position=SplitNode(节点,box.width,box.height);
}
其他的
{
box.position=growtnode(box.width,box.height);
}
}
}
专用节点FindNode(节点rootNode,双w,双h)
{
if(rootNode.used)
{
var nextNode=FindNode(rootNode.right,w,h);
if(nextNode==null)
{
nextNode=FindNode(rootNode.down,w,h);
}
返回下一个节点;
}
否则,如果(w除非我理解错了什么,它会不会只是两个测试而不是一个
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);
我将旋转变量添加到节点
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;
}
}
auto temp=width;width=height;height=temp
?@0liveradam8我知道如何旋转矩形,我不知道如何自动控制它并检查可用的旋转。不相关的是,为什么area
不是一个计算属性?public double area=>height*width;
在节点中添加一个变量,如果它旋转或ot.保留side1
和side2
并根据节点是否旋转显示宽度和高度
。@johnalexi您可以用一段代码演示一个示例,我已经在节点中添加了一个旋转的bool变量,但无法获得其余的变量。我尝试了第一个变量,但没有成功是第二个,因为我没有一个叫做GetBestNode的方法,你是在告诉我创建一个吗?是的,你需要提供这样一个方法。只有当树不可变时,它才能正常工作,而在你的例子中似乎不是这样。是的,它不断地发生变异,我想这对我不起作用。
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);
}
}
}