Some minor cosmetic fixes; improved several variable names; added more commentation

git-svn-id: file:///srv/devel/repo-conversion/nusu@27 d2e56fa2-650e-0410-a79f-9358c0239efd
This commit is contained in:
Markus Ewald 2007-05-28 18:11:41 +00:00
parent 02cea246b5
commit d977552d8f
5 changed files with 49 additions and 37 deletions

View File

@ -37,7 +37,7 @@ namespace Nuclex.Support.Packing {
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");
}
/// <summary>Tests the packer's stability by running a complete benchmark</summary>

View File

@ -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);
@ -209,7 +209,8 @@ namespace Nuclex.Support.Packing {
}
/// <summary>
/// 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.
/// </summary>
/// <param name="rectangleWidth">Width of the rectangle to be placed</param>
/// <param name="rectangleHeight">Height of the rectangle to be placed</param>
@ -217,7 +218,7 @@ namespace Nuclex.Support.Packing {
/// <param name="testedPackingAreaHeight">Height of the tested packing area</param>
/// <returns>
/// 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.
/// </returns>
private int selectAnchorRecursive(
int rectangleWidth, int rectangleHeight,
@ -284,12 +285,12 @@ namespace Nuclex.Support.Packing {
/// <summary>Locates the first free anchor at which the rectangle fits</summary>
/// <param name="rectangleWidth">Width of the rectangle to be placed</param>
/// <param name="rectangleHeight">Height of the rectangle to be placed</param>
/// <param name="packingAreaWidth">Total width of the packing area</param>
/// <param name="packingAreaHeight">Total height of the packing area</param>
/// <param name="testedPackingAreaWidth">Total width of the packing area</param>
/// <param name="testedPackingAreaHeight">Total height of the packing area</param>
/// <returns>The index of the first free anchor or -1 if none is found</returns>
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.
/// </summary>
/// <param name="rectangle">Rectangle whose position to check</param>
/// <param name="packingAreaWidth">Total width of the packing area</param>
/// <param name="packingAreaHeight">Total height of the packing area</param>
/// <param name="testedPackingAreaWidth">Total width of the packing area</param>
/// <param name="testedPackingAreaHeight">Total height of the packing area</param>
/// <returns>True if the rectangle can be placed at its current position</returns>
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;

View File

@ -28,15 +28,20 @@ namespace Nuclex.Support.Packing {
/// <remarks>
/// <para>
/// 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 :)
/// </para>
/// <para>
/// 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.
/// </para>
/// <para>
/// 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.
/// </para>
/// </remarks>
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 {
/// <summary>Finds the best position for a rectangle of the given width</summary>
/// <param name="rectangleWidth">Width of the rectangle to find a position for</param>
/// <param name="rectangleHeight">Height of the rectangle to find a position for</param>
/// <returns>The best position for a rectangle with the specified width</returns>
private bool findBestPosition(
/// <returns>The best position for a rectangle of the specified dimensions</returns>
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
}

View File

@ -37,7 +37,7 @@ namespace Nuclex.Support.Packing {
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");
}
/// <summary>Tests the packer's stability by running a complete benchmark</summary>