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);
            }
        }
    }