Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
GuillotinePacker.cs
Go to the documentation of this file.
1 // Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
2 // This file is distributed under GPL v3. See LICENSE.md for details.
3 
4 using System.Collections.Generic;
5 
6 using SiliconStudio.Core.Mathematics;
7 
8 namespace SiliconStudio.Paradox.Effects.Modules.Processors
9 {
10  /// <summary>
11  /// Implementation of a "Guillotine" packer.
12  /// More information at http://clb.demon.fi/files/RectangleBinPack.pdf.
13  /// </summary>
14  internal class GuillotinePacker
15  {
16  private readonly List<Rectangle> freeRectangles = new List<Rectangle>();
17  private readonly List<Rectangle> tempFreeRectangles = new List<Rectangle>();
18 
19  public int Width { get; private set; }
20  public int Height { get; private set; }
21 
22  public void Clear(int width, int height)
23  {
24  freeRectangles.Clear();
25  freeRectangles.Add(new Rectangle { X = 0, Y = 0, Width = width, Height = height });
26 
27  Width = width;
28  Height = height;
29  }
30 
31  public void Clear()
32  {
33  Clear(Width, Height);
34  }
35 
36  public void Free(ref Rectangle oldRectangle)
37  {
38  freeRectangles.Add(oldRectangle);
39  }
40 
41  public bool Insert(int width, int height, ref Rectangle bestRectangle)
42  {
43  return Insert(width, height, freeRectangles, ref bestRectangle);
44  }
45 
46  public bool TryInsert(int width, int height, int count)
47  {
48  var bestRectangle = new Rectangle();
49  tempFreeRectangles.Clear();
50  tempFreeRectangles.AddRange(freeRectangles);
51 
52  for (var i = 0; i < count; ++i)
53  {
54  if (!Insert(width, height, tempFreeRectangles, ref bestRectangle))
55  {
56  tempFreeRectangles.Clear();
57  return false;
58  }
59  }
60 
61  // if the insertion went well, use the new configuration
62  freeRectangles.Clear();
63  freeRectangles.AddRange(tempFreeRectangles);
64  tempFreeRectangles.Clear();
65 
66  return true;
67  }
68 
69  private static bool Insert(int width, int height, List<Rectangle> freeRectanglesList , ref Rectangle bestRectangle)
70  {
71  // Info on algorithm: http://clb.demon.fi/files/RectangleBinPack.pdf
72  int bestScore = int.MaxValue;
73  int freeRectangleIndex = -1;
74 
75  // Find space for new rectangle
76  for (int i = 0; i < freeRectanglesList.Count; ++i)
77  {
78  var currentFreeRectangle = freeRectanglesList[i];
79  if (width == currentFreeRectangle.Width && height == currentFreeRectangle.Height)
80  {
81  // Perfect fit
82  bestRectangle.X = currentFreeRectangle.X;
83  bestRectangle.Y = currentFreeRectangle.Y;
84  bestRectangle.Width = width;
85  bestRectangle.Height = height;
86  freeRectangleIndex = i;
87  break;
88  }
89  if (width <= currentFreeRectangle.Width && height <= currentFreeRectangle.Height)
90  {
91  // Can fit inside
92  // Use "BAF" heuristic (best area fit)
93  var score = currentFreeRectangle.Width * currentFreeRectangle.Height - width * height;
94  if (score < bestScore)
95  {
96  bestRectangle.X = currentFreeRectangle.X;
97  bestRectangle.Y = currentFreeRectangle.Y;
98  bestRectangle.Width = width;
99  bestRectangle.Height = height;
100  bestScore = score;
101  freeRectangleIndex = i;
102  }
103  }
104  }
105 
106  // No space could be found
107  if (freeRectangleIndex == -1)
108  return false;
109 
110  var freeRectangle = freeRectanglesList[freeRectangleIndex];
111 
112  // Choose an axis to split (trying to minimize the smaller area "MINAS")
113  int w = freeRectangle.Width - bestRectangle.Width;
114  int h = freeRectangle.Height - bestRectangle.Height;
115  var splitHorizontal = (bestRectangle.Width * h > w * bestRectangle.Height);
116 
117  // Form the two new rectangles.
118  var bottom = new Rectangle { X = freeRectangle.X, Y = freeRectangle.Y + bestRectangle.Height, Width = splitHorizontal ? freeRectangle.Width : bestRectangle.Width, Height = h };
119  var right = new Rectangle { X = freeRectangle.X + bestRectangle.Width, Y = freeRectangle.Y, Width = w, Height = splitHorizontal ? bestRectangle.Height : freeRectangle.Height };
120 
121  if (bottom.Width > 0 && bottom.Height > 0)
122  freeRectanglesList.Add(bottom);
123  if (right.Width > 0 && right.Height > 0)
124  freeRectanglesList.Add(right);
125 
126  // Remove previously selected freeRectangle
127  if (freeRectangleIndex != freeRectanglesList.Count - 1)
128  freeRectanglesList[freeRectangleIndex] = freeRectanglesList[freeRectanglesList.Count - 1];
129  freeRectanglesList.RemoveAt(freeRectanglesList.Count - 1);
130 
131  return true;
132  }
133  }
134 }
Represent a gesture that has a random shape.
_In_ size_t count
Definition: DirectXTexP.h:174
System.Windows.Shapes.Rectangle Rectangle
Definition: ColorPicker.cs:16
Structure using the same layout than System.Drawing.Rectangle
Definition: Rectangle.cs:35