diff --git a/Source/Packing/ArevaloRectanglePacker.Test.cs b/Source/Packing/ArevaloRectanglePacker.Test.cs
index 5b66cf6..eb18bda 100644
--- a/Source/Packing/ArevaloRectanglePacker.Test.cs
+++ b/Source/Packing/ArevaloRectanglePacker.Test.cs
@@ -36,8 +36,8 @@ namespace Nuclex.Support.Packing {
[Test]
public void TestSpaceEfficiency() {
float efficiency = CalculateEfficiency(new ArevaloRectanglePacker(70, 70));
-
- Assert.GreaterOrEqual(efficiency, 0.75, "Packer achieves 75% efficiency");
+
+ Assert.GreaterOrEqual(efficiency, 0.75f, "Packer achieves 75% efficiency");
}
/// Tests the packer's stability by running a complete benchmark
diff --git a/Source/Packing/ArevaloRectanglePacker.cs b/Source/Packing/ArevaloRectanglePacker.cs
index 21ee988..9bfeed3 100644
--- a/Source/Packing/ArevaloRectanglePacker.cs
+++ b/Source/Packing/ArevaloRectanglePacker.cs
@@ -147,7 +147,7 @@ namespace Nuclex.Support.Packing {
// positions of the new rectangle
{
// The anchor is only removed if the placement optimization didn't
- // move the rectangle so far that the anchor isn't used at all
+ // move the rectangle so far that the anchor isn't blocked anymore
bool blocksAnchor =
((placement.X + rectangleWidth) > this.anchors[anchorIndex].X) &&
((placement.Y + rectangleHeight) > this.anchors[anchorIndex].Y);
@@ -165,8 +165,8 @@ namespace Nuclex.Support.Packing {
new Rectangle(placement.X, placement.Y, rectangleWidth, rectangleHeight)
);
- return true;
-
+ return true;
+
}
///
@@ -209,7 +209,8 @@ namespace Nuclex.Support.Packing {
}
///
- /// Searches for a free anchor and enlarges the packing area if none can be found
+ /// Searches for a free anchor and recursively enlarges the packing area
+ /// if none can be found.
///
/// Width of the rectangle to be placed
/// Height of the rectangle to be placed
@@ -217,7 +218,7 @@ namespace Nuclex.Support.Packing {
/// Height of the tested packing area
///
/// Index of the anchor the rectangle is to be placed at or -1 if the rectangle
- /// does not fit in the packing area anymore
+ /// does not fit in the packing area anymore.
///
private int selectAnchorRecursive(
int rectangleWidth, int rectangleHeight,
@@ -248,13 +249,13 @@ namespace Nuclex.Support.Packing {
// any further in its width and in its height
bool canEnlargeWidth = (testedPackingAreaWidth < PackingAreaWidth);
bool canEnlargeHeight = (testedPackingAreaHeight < PackingAreaHeight);
-
+
// Try to enlarge the smaller of the two dimensions first (unless the smaller
// dimension is already at its maximum size)
if(
canEnlargeHeight && (
(testedPackingAreaHeight < testedPackingAreaWidth) || !canEnlargeWidth
- )
+ )
) {
// Try to double the height of the packing area
@@ -284,12 +285,12 @@ namespace Nuclex.Support.Packing {
/// Locates the first free anchor at which the rectangle fits
/// Width of the rectangle to be placed
/// Height of the rectangle to be placed
- /// Total width of the packing area
- /// Total height of the packing area
+ /// Total width of the packing area
+ /// Total height of the packing area
/// The index of the first free anchor or -1 if none is found
private int findFirstFreeAnchor(
int rectangleWidth, int rectangleHeight,
- int packingAreaWidth, int packingAreaHeight
+ int testedPackingAreaWidth, int testedPackingAreaHeight
) {
Rectangle potentialLocation = new Rectangle(
0, 0, rectangleWidth, rectangleHeight
@@ -303,7 +304,7 @@ namespace Nuclex.Support.Packing {
potentialLocation.Y = this.anchors[index].Y;
// See if the rectangle would fit in at this anchor point
- if(isFree(ref potentialLocation, packingAreaWidth, packingAreaHeight))
+ if(isFree(ref potentialLocation, testedPackingAreaWidth, testedPackingAreaHeight))
return index;
}
@@ -316,11 +317,11 @@ namespace Nuclex.Support.Packing {
/// at its current location.
///
/// Rectangle whose position to check
- /// Total width of the packing area
- /// Total height of the packing area
+ /// Total width of the packing area
+ /// Total height of the packing area
/// True if the rectangle can be placed at its current position
private bool isFree(
- ref Rectangle rectangle, int packingAreaWidth, int packingAreaHeight
+ ref Rectangle rectangle, int testedPackingAreaWidth, int testedPackingAreaHeight
) {
// If the rectangle is partially or completely outside of the packing
@@ -328,8 +329,8 @@ namespace Nuclex.Support.Packing {
bool leavesPackingArea =
(rectangle.X < 0) ||
(rectangle.Y < 0) ||
- (rectangle.Right >= packingAreaWidth) ||
- (rectangle.Bottom >= packingAreaHeight);
+ (rectangle.Right >= testedPackingAreaWidth) ||
+ (rectangle.Bottom >= testedPackingAreaHeight);
if(leavesPackingArea)
return false;
diff --git a/Source/Packing/CygonRectanglePacker.cs b/Source/Packing/CygonRectanglePacker.cs
index eee6dc9..0acdadd 100644
--- a/Source/Packing/CygonRectanglePacker.cs
+++ b/Source/Packing/CygonRectanglePacker.cs
@@ -28,15 +28,20 @@ namespace Nuclex.Support.Packing {
///
///
/// Algorithm conceived by Markus Ewald (cygon at nuclex dot org), thought
- /// I'm quite sure I'm not the first one to invent this algorithm :)
+ /// I'm quite sure I'm not the first one to come up with it :)
///
///
- /// This algorithm always places rectangles as low as possible. So, for any
- /// new rectangle that is to be added into the packing area, the packer has
- /// to determine the X coordinate at which the rectangle has the lowest height.
- /// To quickly discover these locations, the packer keeps a dynamically updated
- /// list of "height slices" which store the silhouette of the rectangles that
- /// have been placed so far.
+ /// The algorithm always places rectangles as low as possible in the packing
+ /// area. So, for any new rectangle that is to be added into the packing area,
+ /// the packer has to determine the X coordinate at which the rectangle can have
+ /// lowest overall height without overlapping any other rectangles.
+ ///
+ ///
+ /// To quickly discover these locations, the packer uses a sophisticated
+ /// data structure that stores the upper silhouette of the packing area. When
+ /// a new rectangle needs to be added, only the silouette edges need to be
+ /// analyzed to find the position where the rectangle would achieve the lowest
+ /// placement possible in the packing area.
///
///
public class CygonRectanglePacker : RectanglePacker {
@@ -91,7 +96,11 @@ namespace Nuclex.Support.Packing {
return false;
}
- bool fits = findBestPosition(rectangleWidth, rectangleHeight, out placement);
+ // Determine the placement for the new rectangle
+ bool fits = findBestPlacement(rectangleWidth, rectangleHeight, out placement);
+
+ // If a place for the rectangle could be found, update the height slice table to
+ // mark the region of the rectangle as being taken.
if(fits)
integrateRectangle(placement.X, rectangleWidth, placement.Y + rectangleHeight);
@@ -101,8 +110,8 @@ namespace Nuclex.Support.Packing {
/// Finds the best position for a rectangle of the given width
/// Width of the rectangle to find a position for
/// Height of the rectangle to find a position for
- /// The best position for a rectangle with the specified width
- private bool findBestPosition(
+ /// The best position for a rectangle of the specified dimensions
+ private bool findBestPlacement(
int rectangleWidth, int rectangleHeight, out Point placement
) {
@@ -136,6 +145,7 @@ namespace Nuclex.Support.Packing {
if(this.heightSlices[index].Y > highest)
highest = this.heightSlices[index].Y;
+ // Only process this position if it doesn't leave the packing area
if((highest + rectangleHeight < PackingAreaHeight)) {
int score = highest;
@@ -151,7 +161,7 @@ namespace Nuclex.Support.Packing {
if(leftSliceIndex >= this.heightSlices.Count)
break;
- // Advance the ending slice until we're on the right slice again, given the new
+ // Advance the ending slice until we're on the proper slice again, given the new
// starting position of the rectangle.
int rightRectangleEnd = this.heightSlices[leftSliceIndex].X + rectangleWidth;
for(; rightSliceIndex <= this.heightSlices.Count; ++rightSliceIndex) {
@@ -171,10 +181,11 @@ namespace Nuclex.Support.Packing {
if(rightSliceIndex > this.heightSlices.Count)
break;
- }
+ } // while rightSliceIndex <= this.heightSlices.Count
- // Return the index of the best slice we found for this rectangle. If the rectangle
- // didn't fit, this variable will still have its initialization value of -1.
+ // Return the best placement we found for this rectangle. If the rectangle
+ // didn't fit anywhere, the slice index will still have its initialization value
+ // of -1 and we can report that no placement could be found.
if(bestSliceIndex == -1) {
placement = Point.Zero;
return false;
@@ -258,9 +269,9 @@ namespace Nuclex.Support.Packing {
if(right < PackingAreaWidth)
this.heightSlices.Insert(startSlice, new Point(right, returnHeight));
- }
+ } // if endSlice > 0
- }
+ } // if startSlice >= this.heightSlices.Count
}
diff --git a/Source/Packing/RectanglePacker.Test.cs b/Source/Packing/RectanglePacker.Test.cs
index fa6db4b..2cf99ef 100644
--- a/Source/Packing/RectanglePacker.Test.cs
+++ b/Source/Packing/RectanglePacker.Test.cs
@@ -80,7 +80,7 @@ namespace Nuclex.Support.Packing {
RectanglePacker packer = buildPacker();
// Try to cramp as many rectangles into the packing area as possible
- for(;; ++rectanglesPacked) {
+ for(; ; ++rectanglesPacked) {
Point placement;
int width = dimensionGenerator.Next(16, 64);
diff --git a/Source/Packing/SimpleRectanglePacker.Test.cs b/Source/Packing/SimpleRectanglePacker.Test.cs
index ee028c4..9784e53 100644
--- a/Source/Packing/SimpleRectanglePacker.Test.cs
+++ b/Source/Packing/SimpleRectanglePacker.Test.cs
@@ -36,8 +36,8 @@ namespace Nuclex.Support.Packing {
[Test]
public void TestSpaceEfficiency() {
float efficiency = CalculateEfficiency(new SimpleRectanglePacker(70, 70));
-
- Assert.GreaterOrEqual(efficiency, 0.75, "Packer achieves 75% efficiency");
+
+ Assert.GreaterOrEqual(efficiency, 0.75f, "Packer achieves 75% efficiency");
}
/// Tests the packer's stability by running a complete benchmark