Example #1
0
        private void SplitFreeCuboidAlongAxis(
            Cuboid freeCuboid,
            Cuboid placedCuboid,
            bool splitHorizontal)
        {
            var bottom = new Cuboid();

            bottom.X      = freeCuboid.X;
            bottom.Y      = freeCuboid.Y;
            bottom.Z      = freeCuboid.Z + placedCuboid.Depth;
            bottom.Depth  = freeCuboid.Depth - placedCuboid.Depth;
            bottom.Height = placedCuboid.Height;

            var right = new Cuboid();

            right.X      = freeCuboid.X + placedCuboid.Width;
            right.Y      = freeCuboid.Y;
            right.Z      = freeCuboid.Z;
            right.Width  = freeCuboid.Width - placedCuboid.Width;
            right.Height = placedCuboid.Height;

            var top = new Cuboid();

            top.X      = freeCuboid.X;
            top.Y      = freeCuboid.Y + placedCuboid.Height;
            top.Z      = freeCuboid.Z;
            top.Height = freeCuboid.Height - placedCuboid.Height;
            top.Width  = freeCuboid.Width;
            top.Depth  = freeCuboid.Depth;

            if (splitHorizontal)
            {
                bottom.Width = freeCuboid.Width;
                right.Depth  = placedCuboid.Depth;
            }
            else // Split vertically
            {
                bottom.Width = placedCuboid.Width;
                right.Depth  = freeCuboid.Depth;
            }

            // Add new free cuboids.
            if (bottom.Width > 0 && bottom.Height > 0 && bottom.Depth > 0)
            {
                AddFreeCuboid(bottom);
            }
            if (right.Width > 0 && right.Height > 0 && right.Depth > 0)
            {
                AddFreeCuboid(right);
            }
            if (top.Width > 0 && top.Height > 0 && top.Depth > 0)
            {
                AddFreeCuboid(top);
            }
        }
Example #2
0
        private decimal ScoreByHeuristic(
            Cuboid cuboid,
            Cuboid freeCuboid,
            FreeCuboidChoiceHeuristic cuboidChoice)
        {
            switch (cuboidChoice)
            {
            case FreeCuboidChoiceHeuristic.CuboidMinHeight:
                return(freeCuboid.Y + cuboid.Height);

            default:
                throw new NotSupportedException($"cuboid choice is unsupported: {cuboidChoice}");
            }
        }
Example #3
0
 private void AddFreeCuboid(Cuboid freeCuboid)
 {
     if (freeCuboid.X < 0 || freeCuboid.Y < 0 || freeCuboid.Z < 0)
     {
         throw new ArithmeticException(
                   $"add free cuboid failed: negative position, algorithm: {this}, cuboid: {freeCuboid}");
     }
     if (freeCuboid.X + freeCuboid.Width > _binWidth ||
         freeCuboid.Y + freeCuboid.Height > _binHeight ||
         freeCuboid.Z + freeCuboid.Depth > _binDepth)
     {
         throw new ArithmeticException(
                   $"add free cuboid failed: out of bin, algorithm: {this}, cuboid: {freeCuboid}");
     }
     _freeCuboids.Add(freeCuboid);
 }
Example #4
0
        private void SplitFreeCuboidByHeuristic(
            Cuboid freeCuboid,
            Cuboid placedCuboid,
            GuillotineSplitHeuristic method)
        {
            // Compute the lengths of the leftover area.
            var w = freeCuboid.Width - placedCuboid.Width;
            var d = freeCuboid.Depth - placedCuboid.Depth;

            // Use the given heuristic to decide which choice to make.

            bool splitHorizontal;

            switch (method)
            {
            case GuillotineSplitHeuristic.SplitShorterLeftoverAxis:
                // Split along the shorter leftover axis.
                splitHorizontal = (w <= d);
                break;

            case GuillotineSplitHeuristic.SplitLongerLeftoverAxis:
                // Split along the longer leftover axis.
                splitHorizontal = (w > d);
                break;

            case GuillotineSplitHeuristic.SplitShorterAxis:
                // Split along the shorter total axis.
                splitHorizontal = (freeCuboid.Width <= freeCuboid.Depth);
                break;

            case GuillotineSplitHeuristic.SplitLongerAxis:
                // Split along the longer total axis.
                splitHorizontal = (freeCuboid.Width > freeCuboid.Depth);
                break;

            default:
                throw new NotSupportedException($"split method is unsupported: {method}");
            }

            // Perform the actual split.
            SplitFreeCuboidAlongAxis(freeCuboid, placedCuboid, splitHorizontal);
        }
        private void Insert(Cuboid cuboid, ShelfChoiceHeuristic method)
        {
            switch (method)
            {
            case ShelfChoiceHeuristic.ShelfNextFit:
                PutOnShelf(_shelves.Last(), cuboid);
                if (cuboid.IsPlaced)
                {
                    AddToShelf(_shelves.Last(), cuboid);
                    return;
                }
                break;

            case ShelfChoiceHeuristic.ShelfFirstFit:
                foreach (var shelf in _shelves)
                {
                    PutOnShelf(shelf, cuboid);
                    if (cuboid.IsPlaced)
                    {
                        AddToShelf(shelf, cuboid);
                        return;
                    }
                }
                break;
            }

            // The rectangle did not fit on any of the shelves. Open a new shelf.

            // Sort edges in decreasing order
            var edges = new List <decimal>()
            {
                cuboid.Width, cuboid.Height, cuboid.Depth
            };

            edges.Sort();
            var max    = edges[2];
            var middle = edges[1];
            var min    = edges[0];

            var whdSet = new[]
            {
                new { w = middle, h = max, d = min },
                new { w = max, h = middle, d = min },
                new { w = middle, h = min, d = max }
            };

            foreach (var whd in whdSet)
            {
                cuboid.Width  = whd.w;
                cuboid.Height = whd.h;
                cuboid.Depth  = whd.d;
                if (CanStartNewShelf(cuboid.Height))
                {
                    StartNewShelf(cuboid.Height);
                    PutOnShelf(_shelves.Last(), cuboid);
                    if (cuboid.IsPlaced)
                    {
                        AddToShelf(_shelves.Last(), cuboid);
                        return;
                    }
                }
            }

            // The rectangle didn't fit.
        }
        private void PutOnShelf(Shelf shelf, Cuboid cuboid)
        {
            var width  = cuboid.Width;
            var height = cuboid.Height;
            var depth  = cuboid.Depth;

            // Sort edges in decreasing order
            var edges = new List <decimal>()
            {
                width, height, depth
            };

            edges.Sort();
            var max    = edges[2];
            var middle = edges[1];
            var min    = edges[0];

            // Set cuboid's longest egde vertically
            if (max > shelf.Height)
            {
                // pass
            }
            else
            {
                var maxVerticalRect = new Rectangle(middle, min, 0, 0);
                var freeRectIndex   = 0;
                shelf.Guillotine.Insert(maxVerticalRect, _rectChoice, out freeRectIndex);
                if (maxVerticalRect.IsPlaced)
                {
                    shelf.Guillotine.InsertOnPosition(maxVerticalRect, _splitMethod, freeRectIndex);
                    cuboid.IsPlaced = true;
                    cuboid.Width    = maxVerticalRect.Width;
                    cuboid.Height   = max;
                    cuboid.Depth    = maxVerticalRect.Height;
                    cuboid.X        = maxVerticalRect.X;
                    cuboid.Z        = maxVerticalRect.Y;
                    return;
                }
            }

            // Set cuboid's second longest egde vertically
            if (middle > shelf.Height)
            {
                // pass
            }
            else
            {
                var middleVerticalRect = new Rectangle(min, max, 0, 0);
                var freeRectIndex      = 0;
                shelf.Guillotine.Insert(middleVerticalRect, _rectChoice, out freeRectIndex);
                if (middleVerticalRect.IsPlaced)
                {
                    shelf.Guillotine.InsertOnPosition(middleVerticalRect, _splitMethod, freeRectIndex);
                    cuboid.IsPlaced = true;
                    cuboid.Width    = middleVerticalRect.Width;
                    cuboid.Height   = middle;
                    cuboid.Depth    = middleVerticalRect.Height;
                    cuboid.X        = middleVerticalRect.X;
                    cuboid.Z        = middleVerticalRect.Y;
                    return;
                }
            }

            // Set cuboid's smallest egde vertically
            if (min > shelf.Height)
            {
                // pass
            }
            else
            {
                var minVerticalRect = new Rectangle(middle, max, 0, 0);
                var freeRectIndex   = 0;
                shelf.Guillotine.Insert(minVerticalRect, _rectChoice, out freeRectIndex);
                if (minVerticalRect.IsPlaced)
                {
                    shelf.Guillotine.InsertOnPosition(minVerticalRect, _splitMethod, freeRectIndex);
                    cuboid.IsPlaced = true;
                    cuboid.Width    = minVerticalRect.Width;
                    cuboid.Height   = min;
                    cuboid.Depth    = minVerticalRect.Height;
                    cuboid.X        = minVerticalRect.X;
                    cuboid.Z        = minVerticalRect.Y;
                    return;
                }
            }

            // Place failed
        }
Example #7
0
        private void FindPositionForNewNode(
            Cuboid cuboid,
            FreeCuboidChoiceHeuristic cuboidChoice,
            out int freeCuboidIndex)
        {
            var width     = cuboid.Width;
            var height    = cuboid.Height;
            var depth     = cuboid.Depth;
            var bestScore = decimal.MaxValue;

            freeCuboidIndex = -1;

            // Try each free cuboid to find the best one for placement a given cuboid.
            // Rotate a cuboid in every possible way and find which choice is the best.
            for (int index = 0; index < _freeCuboids.Count; ++index)
            {
                var freeCuboid = _freeCuboids[index];

                // Width x Height x Depth
                if (width <= freeCuboid.Width &&
                    height <= freeCuboid.Height &&
                    depth <= freeCuboid.Depth)
                {
                    var score = ScoreByHeuristic(cuboid, freeCuboid, cuboidChoice);
                    if (score < bestScore)
                    {
                        cuboid.IsPlaced = true;
                        cuboid.X        = freeCuboid.X;
                        cuboid.Y        = freeCuboid.Y;
                        cuboid.Z        = freeCuboid.Z;
                        cuboid.Width    = width;
                        cuboid.Height   = height;
                        cuboid.Depth    = depth;
                        bestScore       = score;
                        freeCuboidIndex = index;
                    }
                }

                // Width x Depth x Height
                if (width <= freeCuboid.Width &&
                    depth <= freeCuboid.Height &&
                    height <= freeCuboid.Depth)
                {
                    var score = ScoreByHeuristic(cuboid, freeCuboid, cuboidChoice);
                    if (score < bestScore)
                    {
                        cuboid.IsPlaced = true;
                        cuboid.X        = freeCuboid.X;
                        cuboid.Y        = freeCuboid.Y;
                        cuboid.Z        = freeCuboid.Z;
                        cuboid.Width    = width;
                        cuboid.Height   = depth;
                        cuboid.Depth    = height;
                        bestScore       = score;
                        freeCuboidIndex = index;
                    }
                }

                // Depth x Height x Width
                if (depth <= freeCuboid.Width &&
                    height <= freeCuboid.Height &&
                    width <= freeCuboid.Depth)
                {
                    var score = ScoreByHeuristic(cuboid, freeCuboid, cuboidChoice);
                    if (score < bestScore)
                    {
                        cuboid.IsPlaced = true;
                        cuboid.X        = freeCuboid.X;
                        cuboid.Y        = freeCuboid.Y;
                        cuboid.Z        = freeCuboid.Z;
                        cuboid.Width    = depth;
                        cuboid.Height   = height;
                        cuboid.Depth    = width;
                        bestScore       = score;
                        freeCuboidIndex = index;
                    }
                }

                // Depth x Width x Height
                if (depth <= freeCuboid.Width &&
                    width <= freeCuboid.Height &&
                    height <= freeCuboid.Depth)
                {
                    var score = ScoreByHeuristic(cuboid, freeCuboid, cuboidChoice);
                    if (score < bestScore)
                    {
                        cuboid.IsPlaced = true;
                        cuboid.X        = freeCuboid.X;
                        cuboid.Y        = freeCuboid.Y;
                        cuboid.Z        = freeCuboid.Z;
                        cuboid.Width    = depth;
                        cuboid.Height   = width;
                        cuboid.Depth    = height;
                        bestScore       = score;
                        freeCuboidIndex = index;
                    }
                }

                // Height x Width x Depth
                if (height <= freeCuboid.Width &&
                    width <= freeCuboid.Height &&
                    depth <= freeCuboid.Depth)
                {
                    var score = ScoreByHeuristic(cuboid, freeCuboid, cuboidChoice);
                    if (score < bestScore)
                    {
                        cuboid.IsPlaced = true;
                        cuboid.X        = freeCuboid.X;
                        cuboid.Y        = freeCuboid.Y;
                        cuboid.Z        = freeCuboid.Z;
                        cuboid.Width    = height;
                        cuboid.Height   = width;
                        cuboid.Depth    = depth;
                        bestScore       = score;
                        freeCuboidIndex = index;
                    }
                }

                // Height x Depth x Width
                if (height <= freeCuboid.Width &&
                    depth <= freeCuboid.Height &&
                    width <= freeCuboid.Depth)
                {
                    var score = ScoreByHeuristic(cuboid, freeCuboid, cuboidChoice);
                    if (score < bestScore)
                    {
                        cuboid.IsPlaced = true;
                        cuboid.X        = freeCuboid.X;
                        cuboid.Y        = freeCuboid.Y;
                        cuboid.Z        = freeCuboid.Z;
                        cuboid.Width    = height;
                        cuboid.Height   = depth;
                        cuboid.Depth    = width;
                        bestScore       = score;
                        freeCuboidIndex = index;
                    }
                }
            }
        }