Finally disabled wasted area calculation for good in the 'cygon' packer because benchmarks show it as being counterproductive; implemented rectangle placement optimization as it is done in the original 'arevalo' packer - the C# version should now produce the exact identical results the C++ version does
git-svn-id: file:///srv/devel/repo-conversion/nusu@25 d2e56fa2-650e-0410-a79f-9358c0239efd
This commit is contained in:
parent
dbc1da27a8
commit
9157bf8454
|
@ -31,7 +31,7 @@
|
||||||
<DebugType>pdbonly</DebugType>
|
<DebugType>pdbonly</DebugType>
|
||||||
<Optimize>true</Optimize>
|
<Optimize>true</Optimize>
|
||||||
<OutputPath>bin\x86\Release</OutputPath>
|
<OutputPath>bin\x86\Release</OutputPath>
|
||||||
<DefineConstants>TRACE</DefineConstants>
|
<DefineConstants>TRACE;UNITTEST</DefineConstants>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
<NoStdLib>true</NoStdLib>
|
<NoStdLib>true</NoStdLib>
|
||||||
|
|
|
@ -35,11 +35,23 @@ namespace Nuclex.Support.Packing {
|
||||||
/// <summary>Tests the packer's efficiency using a deterministic benchmark</summary>
|
/// <summary>Tests the packer's efficiency using a deterministic benchmark</summary>
|
||||||
[Test]
|
[Test]
|
||||||
public void TestSpaceEfficiency() {
|
public void TestSpaceEfficiency() {
|
||||||
float efficiency = calculateEfficiency(new ArevaloRectanglePacker(70, 70));
|
float efficiency = CalculateEfficiency(new ArevaloRectanglePacker(70, 70));
|
||||||
|
|
||||||
Assert.GreaterOrEqual(efficiency, 0.75, "Packer achieves 75% efficiency");
|
Assert.GreaterOrEqual(efficiency, 0.75, "Packer achieves 75% efficiency");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Tests the packer's stability by running a complete benchmark</summary>
|
||||||
|
[Test]
|
||||||
|
public void TestStability() {
|
||||||
|
float score = Benchmark(
|
||||||
|
delegate() { return new ArevaloRectanglePacker(1024, 1024); }
|
||||||
|
);
|
||||||
|
|
||||||
|
// This is mainly a stability and performance test. It fails when the
|
||||||
|
// packer crashes on its own and is otherwise only there to tell how long
|
||||||
|
// it takes to complete the benchmark.
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Nuclex.Support.Packing
|
} // namespace Nuclex.Support.Packing
|
||||||
|
|
|
@ -137,12 +137,30 @@ namespace Nuclex.Support.Packing {
|
||||||
|
|
||||||
placement = this.anchors[anchorIndex];
|
placement = this.anchors[anchorIndex];
|
||||||
|
|
||||||
|
// Move the rectangle either to the left or to the top until it collides with
|
||||||
|
// a neightbouring rectangle. This is done to combat the effect of lining up
|
||||||
|
// rectangles with gaps to the left or top of them because the anchor that
|
||||||
|
// would allow placement there has been blocked by another rectangle
|
||||||
|
optimizePlacement(ref placement, rectangleWidth, rectangleHeight);
|
||||||
|
|
||||||
// Remove the used anchor and add new anchors at the upper right and lower left
|
// Remove the used anchor and add new anchors at the upper right and lower left
|
||||||
// positions of the new rectangle
|
// 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
|
||||||
|
bool blocksAnchor =
|
||||||
|
((placement.X + rectangleWidth) > this.anchors[anchorIndex].X) &&
|
||||||
|
((placement.Y + rectangleHeight) > this.anchors[anchorIndex].Y);
|
||||||
|
|
||||||
|
if(blocksAnchor)
|
||||||
this.anchors.RemoveAt(anchorIndex);
|
this.anchors.RemoveAt(anchorIndex);
|
||||||
|
|
||||||
|
// Add new anchors at the upper right and lower left coordinates of the rectangle
|
||||||
this.anchors.Add(new Point(placement.X + rectangleWidth, placement.Y));
|
this.anchors.Add(new Point(placement.X + rectangleWidth, placement.Y));
|
||||||
this.anchors.Add(new Point(placement.X, placement.Y + rectangleHeight));
|
this.anchors.Add(new Point(placement.X, placement.Y + rectangleHeight));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, we can add the rectangle to our packed rectangles list
|
||||||
this.packedRectangles.Add(
|
this.packedRectangles.Add(
|
||||||
new Rectangle(placement.X, placement.Y, rectangleWidth, rectangleHeight)
|
new Rectangle(placement.X, placement.Y, rectangleWidth, rectangleHeight)
|
||||||
);
|
);
|
||||||
|
@ -151,55 +169,98 @@ namespace Nuclex.Support.Packing {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Optimizes the rectangle's placement by moving it either left or up to fill
|
||||||
|
/// any gaps resulting from rectangles blocking the anchors of the most optimal
|
||||||
|
/// placements.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="placement">Placement to be optimized</param>
|
||||||
|
/// <param name="rectangleWidth">Width of the rectangle to be optimized</param>
|
||||||
|
/// <param name="rectangleHeight">Height of the rectangle to be optimized</param>
|
||||||
|
private void optimizePlacement(
|
||||||
|
ref Point placement, int rectangleWidth, int rectangleHeight
|
||||||
|
) {
|
||||||
|
Rectangle rectangle = new Rectangle(
|
||||||
|
placement.X, placement.Y, rectangleWidth, rectangleHeight
|
||||||
|
);
|
||||||
|
|
||||||
|
// Try to move the rectangle to the left as far as possible
|
||||||
|
int leftMost = placement.X;
|
||||||
|
while(isFree(ref rectangle, PackingAreaWidth, PackingAreaHeight)) {
|
||||||
|
leftMost = rectangle.X;
|
||||||
|
--rectangle.X;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset rectangle to original position
|
||||||
|
rectangle.X = placement.X;
|
||||||
|
|
||||||
|
// Try to move the rectangle upwards as far as possible
|
||||||
|
int topMost = placement.Y;
|
||||||
|
while(isFree(ref rectangle, PackingAreaWidth, PackingAreaHeight)) {
|
||||||
|
topMost = rectangle.Y;
|
||||||
|
--rectangle.Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the dimension in which the rectangle could be moved farther
|
||||||
|
if((leftMost - placement.X) > (topMost - placement.Y))
|
||||||
|
placement.X = leftMost;
|
||||||
|
else
|
||||||
|
placement.Y = topMost;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Searches for a free anchor and enlarges the packing area if none can be found
|
/// Searches for a free anchor and enlarges the packing area if none can be found
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="rectangleWidth">Width of the rectangle to be placed</param>
|
/// <param name="rectangleWidth">Width of the rectangle to be placed</param>
|
||||||
/// <param name="rectangleHeight">Height 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="testedPackingAreaWidth">Width of the tested packing area</param>
|
||||||
/// <param name="packingAreaHeight">Total height of the packing area</param>
|
/// <param name="testedPackingAreaHeight">Height of the tested packing area</param>
|
||||||
/// <returns>
|
/// <returns>
|
||||||
/// Index of the anchor the rectangle is to be placed at or -1 if the rectangle
|
/// 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>
|
/// </returns>
|
||||||
private int selectAnchorRecursive(
|
private int selectAnchorRecursive(
|
||||||
int rectangleWidth, int rectangleHeight,
|
int rectangleWidth, int rectangleHeight,
|
||||||
int packingAreaWidth, int packingAreaHeight
|
int testedPackingAreaWidth, int testedPackingAreaHeight
|
||||||
) {
|
) {
|
||||||
|
|
||||||
// Try to locate an anchor point where the rectangle fits in
|
// Try to locate an anchor point where the rectangle fits in
|
||||||
int freeAnchorIndex = findFirstFreeAnchor(
|
int freeAnchorIndex = findFirstFreeAnchor(
|
||||||
rectangleWidth, rectangleHeight, packingAreaWidth, packingAreaHeight
|
rectangleWidth, rectangleHeight, testedPackingAreaWidth, testedPackingAreaHeight
|
||||||
);
|
);
|
||||||
|
|
||||||
// If a the rectangle fits without resizing packing area (any further in case
|
// If a the rectangle fits without resizing packing area (any further in case
|
||||||
// of a recursive call), take over the new packing area size and return the
|
// of a recursive call), take over the new packing area size and return the
|
||||||
// anchor at which the rectangle can be placed.
|
// anchor at which the rectangle can be placed.
|
||||||
if(freeAnchorIndex != -1) {
|
if(freeAnchorIndex != -1) {
|
||||||
this.actualPackingAreaWidth = packingAreaWidth;
|
this.actualPackingAreaWidth = testedPackingAreaWidth;
|
||||||
this.actualPackingAreaHeight = packingAreaHeight;
|
this.actualPackingAreaHeight = testedPackingAreaHeight;
|
||||||
|
|
||||||
return freeAnchorIndex;
|
return freeAnchorIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
// If we reach this point, the rectangle did not fit in the current packing
|
// If we reach this point, the rectangle did not fit in the current packing
|
||||||
// area and our only choice is to try and enlarge the packing area.
|
// area and our only choice is to try and enlarge the packing area.
|
||||||
|
//
|
||||||
|
|
||||||
bool canEnlargeWidth = (packingAreaWidth < PackingAreaWidth);
|
// For readability, determine whether the packing area can be enlarged
|
||||||
bool canEnlargeHeight = (packingAreaHeight < PackingAreaHeight);
|
// 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
|
// Try to enlarge the smaller of the two dimensions first (unless the smaller
|
||||||
// dimension is already at its maximum size)
|
// dimension is already at its maximum size)
|
||||||
if(
|
if(
|
||||||
(
|
canEnlargeHeight && (
|
||||||
(packingAreaHeight < packingAreaWidth) || !canEnlargeWidth
|
(testedPackingAreaHeight < testedPackingAreaWidth) || !canEnlargeWidth
|
||||||
) && canEnlargeHeight
|
)
|
||||||
) {
|
) {
|
||||||
|
|
||||||
// Try to double the height of the packing area
|
// Try to double the height of the packing area
|
||||||
return selectAnchorRecursive(
|
return selectAnchorRecursive(
|
||||||
rectangleWidth, rectangleHeight,
|
rectangleWidth, rectangleHeight,
|
||||||
packingAreaWidth, Math.Min(packingAreaHeight * 2, PackingAreaHeight)
|
testedPackingAreaWidth, Math.Min(testedPackingAreaHeight * 2, PackingAreaHeight)
|
||||||
);
|
);
|
||||||
|
|
||||||
} else if(canEnlargeWidth) {
|
} else if(canEnlargeWidth) {
|
||||||
|
@ -207,7 +268,7 @@ namespace Nuclex.Support.Packing {
|
||||||
// Try to double the width of the packing area
|
// Try to double the width of the packing area
|
||||||
return selectAnchorRecursive(
|
return selectAnchorRecursive(
|
||||||
rectangleWidth, rectangleHeight,
|
rectangleWidth, rectangleHeight,
|
||||||
Math.Min(packingAreaWidth * 2, PackingAreaWidth), packingAreaHeight
|
Math.Min(testedPackingAreaWidth * 2, PackingAreaWidth), testedPackingAreaHeight
|
||||||
);
|
);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -262,14 +323,14 @@ namespace Nuclex.Support.Packing {
|
||||||
ref Rectangle rectangle, int packingAreaWidth, int packingAreaHeight
|
ref Rectangle rectangle, int packingAreaWidth, int packingAreaHeight
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
// If the rectangle is partially or completely outside of the packing
|
||||||
|
// area, it can't be placed at its current location
|
||||||
bool leavesPackingArea =
|
bool leavesPackingArea =
|
||||||
(rectangle.X < 0) ||
|
(rectangle.X < 0) ||
|
||||||
(rectangle.Y < 0) ||
|
(rectangle.Y < 0) ||
|
||||||
(rectangle.Right >= packingAreaWidth) ||
|
(rectangle.Right >= packingAreaWidth) ||
|
||||||
(rectangle.Bottom >= packingAreaHeight);
|
(rectangle.Bottom >= packingAreaHeight);
|
||||||
|
|
||||||
// If the rectangle is partially or completely outside of the packing
|
|
||||||
// area, it can't be placed at its current location
|
|
||||||
if(leavesPackingArea)
|
if(leavesPackingArea)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
|
@ -35,11 +35,23 @@ namespace Nuclex.Support.Packing {
|
||||||
/// <summary>Tests the packer's efficiency using a deterministic benchmark</summary>
|
/// <summary>Tests the packer's efficiency using a deterministic benchmark</summary>
|
||||||
[Test]
|
[Test]
|
||||||
public void TestSpaceEfficiency() {
|
public void TestSpaceEfficiency() {
|
||||||
float efficiency = calculateEfficiency(new CygonRectanglePacker(70, 70));
|
float efficiency = CalculateEfficiency(new CygonRectanglePacker(70, 70));
|
||||||
|
|
||||||
Assert.GreaterOrEqual(efficiency, 0.75f, "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>
|
||||||
|
[Test]
|
||||||
|
public void TestStability() {
|
||||||
|
float score = Benchmark(
|
||||||
|
delegate() { return new CygonRectanglePacker(1024, 1024); }
|
||||||
|
);
|
||||||
|
|
||||||
|
// This is mainly a stability and performance test. It fails when the
|
||||||
|
// packer crashes on its own and is otherwise only there to tell how long
|
||||||
|
// it takes to complete the benchmark.
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Nuclex.Support.Packing
|
} // namespace Nuclex.Support.Packing
|
||||||
|
|
|
@ -41,6 +41,32 @@ namespace Nuclex.Support.Packing {
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public class CygonRectanglePacker : RectanglePacker {
|
public class CygonRectanglePacker : RectanglePacker {
|
||||||
|
|
||||||
|
#if USE_WASTED_AREA
|
||||||
|
// An optimization idea of mine. With this, the packer not only tries to place
|
||||||
|
// rectangles as low in the packing area as possible, it also tried to choose
|
||||||
|
// locations where it doesn't block gaps where other rectangles might still fit
|
||||||
|
// in. This turned out to be counter-productive and a marginal improvement in
|
||||||
|
// space efficiency could be achieved by deliberately choosing positions where
|
||||||
|
// gaps where blocked for future rectangles.
|
||||||
|
//
|
||||||
|
// These are the results of a benchmark with different wastedAreaScoreWeights
|
||||||
|
//
|
||||||
|
// -10 579.315
|
||||||
|
// -5 582.140
|
||||||
|
// -4 582.886
|
||||||
|
// -3 583.166
|
||||||
|
// -2 583.792
|
||||||
|
// -1 583.975 (best)
|
||||||
|
// 0 583.791
|
||||||
|
// 1 583.960
|
||||||
|
// 2 583.469
|
||||||
|
// 3 582.444
|
||||||
|
// 4 580.259
|
||||||
|
// 5 578.400
|
||||||
|
// 10 570.467
|
||||||
|
//
|
||||||
|
// Needless to say, I chose to disable this splendid optimization.
|
||||||
|
|
||||||
/// <summary>By how much the wasted area influences a placement's score</summary>
|
/// <summary>By how much the wasted area influences a placement's score</summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// <para>
|
/// <para>
|
||||||
|
@ -61,7 +87,9 @@ namespace Nuclex.Support.Packing {
|
||||||
/// packing problems is a matter of trial and error, as it seems :)
|
/// packing problems is a matter of trial and error, as it seems :)
|
||||||
/// </para>
|
/// </para>
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
private const int WastedAreaScoreWeight = 3;
|
private const int WastedAreaScoreWeight = 10;
|
||||||
|
|
||||||
|
#endif // USE_WASTED_AREA
|
||||||
|
|
||||||
#region class SliceStartComparer
|
#region class SliceStartComparer
|
||||||
|
|
||||||
|
@ -161,7 +189,7 @@ namespace Nuclex.Support.Packing {
|
||||||
if((highest + rectangleHeight < PackingAreaHeight)) {
|
if((highest + rectangleHeight < PackingAreaHeight)) {
|
||||||
int score = highest;
|
int score = highest;
|
||||||
|
|
||||||
// WASTED AREA CALCULATION --------------------------------------------------
|
#if USE_WASTED_AREA // --------------------------------------------------------
|
||||||
|
|
||||||
// Calculate the amount of space that would go to waste if the rectangle
|
// Calculate the amount of space that would go to waste if the rectangle
|
||||||
// would be placed at this location
|
// would be placed at this location
|
||||||
|
@ -185,7 +213,7 @@ namespace Nuclex.Support.Packing {
|
||||||
// Alter the score by the amount of wasted area in relation to
|
// Alter the score by the amount of wasted area in relation to
|
||||||
score += (wastedArea * WastedAreaScoreWeight / rectangleArea);
|
score += (wastedArea * WastedAreaScoreWeight / rectangleArea);
|
||||||
|
|
||||||
// WASTED AREA CALCULATION --------------------------------------------------
|
#endif // USE_WASTED_AREA -----------------------------------------------------
|
||||||
|
|
||||||
if(score < bestScore) {
|
if(score < bestScore) {
|
||||||
bestSliceIndex = leftSliceIndex;
|
bestSliceIndex = leftSliceIndex;
|
||||||
|
|
|
@ -27,6 +27,10 @@ namespace Nuclex.Support.Packing {
|
||||||
/// <summary>Base class for unit testing the rectangle packers</summary>
|
/// <summary>Base class for unit testing the rectangle packers</summary>
|
||||||
public abstract class RectanglePackerTest {
|
public abstract class RectanglePackerTest {
|
||||||
|
|
||||||
|
/// <summary>Delegate for a Rectangle Packer factory method</summary>
|
||||||
|
/// <returns>A new rectangle packer</returns>
|
||||||
|
protected delegate RectanglePacker BuildRectanglePacker();
|
||||||
|
|
||||||
/// <summary>Determines the efficiency of a packer with a packing area of 70x70</summary>
|
/// <summary>Determines the efficiency of a packer with a packing area of 70x70</summary>
|
||||||
/// <param name="packer">Packer with a packing area of 70x70 units</param>
|
/// <param name="packer">Packer with a packing area of 70x70 units</param>
|
||||||
/// <returns>The efficiency factor of the packer</returns>
|
/// <returns>The efficiency factor of the packer</returns>
|
||||||
|
@ -37,7 +41,7 @@ namespace Nuclex.Support.Packing {
|
||||||
/// the efficiency rating is to 1.0, the better, with 0.99 being the
|
/// the efficiency rating is to 1.0, the better, with 0.99 being the
|
||||||
/// mathematically best rating achievable.
|
/// mathematically best rating achievable.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public float calculateEfficiency(RectanglePacker packer) {
|
protected float CalculateEfficiency(RectanglePacker packer) {
|
||||||
// If we take a 1x1 square, a 2x2 square, etc. up to a 24x24 square,
|
// If we take a 1x1 square, a 2x2 square, etc. up to a 24x24 square,
|
||||||
// the sum of the areas of these squares is 4900, which is 70². This
|
// the sum of the areas of these squares is 4900, which is 70². This
|
||||||
// is the only nontrivial sum of consecutive squares starting with
|
// is the only nontrivial sum of consecutive squares starting with
|
||||||
|
@ -54,6 +58,44 @@ namespace Nuclex.Support.Packing {
|
||||||
return (float)areaCovered / 4900.0f;
|
return (float)areaCovered / 4900.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Benchmarks the provided rectangle packer using random data</summary>
|
||||||
|
/// <param name="packerBuilder">
|
||||||
|
/// Rectangle packer builder returning new rectangle packers
|
||||||
|
/// with an area of 1024 x 1024
|
||||||
|
/// </param>
|
||||||
|
/// <returns>The achieved benchmark score</returns>
|
||||||
|
protected float Benchmark(BuildRectanglePacker packerBuilder) {
|
||||||
|
// How many runs to perform for getting a stable average
|
||||||
|
const int averagingRuns = 200;
|
||||||
|
|
||||||
|
// Generates the random number seeds. This is used so that each run produces
|
||||||
|
// the same number sequences and makes the comparison of different algorithms
|
||||||
|
// a little bit more stable.
|
||||||
|
Random seedGenerator = new Random(12345);
|
||||||
|
int rectanglesPacked = 0;
|
||||||
|
|
||||||
|
// Perform a number of runs to get a semi-stable average score
|
||||||
|
for(int averagingRun = 0; averagingRun < averagingRuns; ++averagingRun) {
|
||||||
|
Random dimensionGenerator = new Random(seedGenerator.Next());
|
||||||
|
RectanglePacker packer = packerBuilder();
|
||||||
|
|
||||||
|
// Try to cramp as many rectangles into the packing area as possible
|
||||||
|
for(;; ++rectanglesPacked) {
|
||||||
|
Point placement;
|
||||||
|
|
||||||
|
int width = dimensionGenerator.Next(16, 64);
|
||||||
|
int height = dimensionGenerator.Next(16, 64);
|
||||||
|
|
||||||
|
// As soon as the packer rejects the first rectangle, the run is over
|
||||||
|
if(!packer.TryPack(width, height, out placement))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the average score achieved by the packer
|
||||||
|
return (float)rectanglesPacked / (float)averagingRuns;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Nuclex.Support.Packing
|
} // namespace Nuclex.Support.Packing
|
||||||
|
|
|
@ -35,11 +35,23 @@ namespace Nuclex.Support.Packing {
|
||||||
/// <summary>Tests the packer's efficiency using a deterministic benchmark</summary>
|
/// <summary>Tests the packer's efficiency using a deterministic benchmark</summary>
|
||||||
[Test]
|
[Test]
|
||||||
public void TestSpaceEfficiency() {
|
public void TestSpaceEfficiency() {
|
||||||
float efficiency = calculateEfficiency(new SimpleRectanglePacker(70, 70));
|
float efficiency = CalculateEfficiency(new SimpleRectanglePacker(70, 70));
|
||||||
|
|
||||||
Assert.GreaterOrEqual(efficiency, 0.75, "Packer achieves 75% efficiency");
|
Assert.GreaterOrEqual(efficiency, 0.75, "Packer achieves 75% efficiency");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Tests the packer's stability by running a complete benchmark</summary>
|
||||||
|
[Test]
|
||||||
|
public void TestStability() {
|
||||||
|
float score = Benchmark(
|
||||||
|
delegate() { return new SimpleRectanglePacker(1024, 1024); }
|
||||||
|
);
|
||||||
|
|
||||||
|
// This is mainly a stability and performance test. It fails when the
|
||||||
|
// packer crashes on its own and is otherwise only there to tell how long
|
||||||
|
// it takes to complete the benchmark.
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Nuclex.Support.Packing
|
} // namespace Nuclex.Support.Packing
|
||||||
|
|
Loading…
Reference in New Issue
Block a user