【问题标题】:C# Binary Tree 2D Packing Algorithm RotationC# 二叉树 2D 打包算法 旋转
【发布时间】:2021-05-18 08:28:59
【问题描述】:

我正在使用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.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;
        }
    }
}

【问题讨论】:

  • auto temp = width; width = height; height = temp?
  • @0liveradam8 我知道如何旋转矩形我不知道如何自动控制它并检查可用的旋转。
  • 不相关,为什么area 不是计算属性? public double Area =&gt; height*width;
  • Node 中添加一个变量,如果它旋转与否。保留side1side2 并根据节点是否旋转显示WidthHeight
  • @JohnAlexiou 你能用一小段代码展示一个例子吗,我已经在 Node 中添加了一个旋转的 bool 变量,但我无法得到其余的。

标签: c# bin-packing


【解决方案1】:

我将旋转变量添加到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);
            }
        }
    }

【讨论】:

    【解决方案2】:

    除非我误解了某些东西,否则它不只是两个测试而不是一个吗?即

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

    【讨论】:

    • 我尝试了第一个它不起作用,但我无法尝试第二个,因为我没有名为 GetBestNode 的方法,你是在告诉我创建一个吗?
    • 是的,您需要提供这样的方法。只有当树不可变时它才能正常工作,而在您的示例中似乎并非如此。
    • 是的,它一直在变异,我猜这对我不起作用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多