diff --git a/Source/Packing/CygonRectanglePacker.cs b/Source/Packing/CygonRectanglePacker.cs
index c1588e1..9b0fb4a 100644
--- a/Source/Packing/CygonRectanglePacker.cs
+++ b/Source/Packing/CygonRectanglePacker.cs
@@ -41,6 +41,28 @@ namespace Nuclex.Support.Packing {
///
public class CygonRectanglePacker : RectanglePacker {
+ /// By how much the wasted area influences a placement's score
+ ///
+ ///
+ /// The score of a potential position for a new rectangle is how far the
+ /// rectangle is from the lower end of the packing area. The lower the
+ /// score, the better the position.
+ ///
+ ///
+ /// Often, however, it's better to choose a position that's farther from
+ /// the lower end of the packing area to not block a gap in which a future
+ /// rectangle might still fit in. To account for this fact, the packer
+ /// calculates a "wasted area factor", which is the amount of area that
+ /// would forever go to waste in relation of the area the rectangle has.
+ ///
+ ///
+ /// This value controls the weighting of this wasted area factor in the
+ /// potential position's score. Finding a value that works well for typical
+ /// packing problems is a matter of trial and error, as it seems :)
+ ///
+ ///
+ private const int WastedAreaScoreWeight = 3;
+
#region class SliceStartComparer
/// Compares the starting position of height slices
@@ -106,6 +128,9 @@ namespace Nuclex.Support.Packing {
int rectangleWidth, int rectangleHeight, out Point placement
) {
+ // Total surface area of the rectangle
+ int rectangleArea = rectangleWidth * rectangleHeight;
+
// Slice index, vertical position and score of the best placement we could find
int bestSliceIndex = -1; // Slice index where the best placement was found
int bestSliceY = 0; // Y position of the best placement found
@@ -137,7 +162,7 @@ namespace Nuclex.Support.Packing {
int score = highest;
// WASTED AREA CALCULATION --------------------------------------------------
-
+
// Calculate the amount of space that would go to waste if the rectangle
// would be placed at this location
int wastedArea = 0;
@@ -152,8 +177,14 @@ namespace Nuclex.Support.Packing {
this.heightSlices[rightSliceIndex - 1].X
);
- score += (int)Math.Sqrt((double)wastedArea) / 10;
-
+ // Limit wasted area to the area taken up by the rectangle. This prevents
+ // a "build-up" of wasted area that become more expensive the higher the packing
+ // area is filled.
+ wastedArea = Math.Min(wastedArea, rectangleArea);
+
+ // Alter the score by the amount of wasted area in relation to
+ score += (wastedArea * WastedAreaScoreWeight / rectangleArea);
+
// WASTED AREA CALCULATION --------------------------------------------------
if(score < bestScore) {
diff --git a/Source/Packing/SimpleRectanglePacker.cs b/Source/Packing/SimpleRectanglePacker.cs
index bdf6590..1396fca 100644
--- a/Source/Packing/SimpleRectanglePacker.cs
+++ b/Source/Packing/SimpleRectanglePacker.cs
@@ -78,6 +78,7 @@ namespace Nuclex.Support.Packing {
this.lineHeight = rectangleHeight;
return true;
+
}
/// Current packing line