Renamed Allocate() methods to Pack() in RectanglePacker; fixed an oversight in Nuclex.Support that made overlapping rectangles possible; reactivated wasted area calculation for 'cygon' rectangle packer
git-svn-id: file:///srv/devel/repo-conversion/nusu@23 d2e56fa2-650e-0410-a79f-9358c0239efd
This commit is contained in:
parent
4fd0680ae7
commit
116fb53b0a
|
@ -27,6 +27,10 @@ namespace Nuclex.Support.Packing {
|
||||||
/// <summary>Rectangle packer using an algorithm by Javier Arevalo</summary>
|
/// <summary>Rectangle packer using an algorithm by Javier Arevalo</summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// <para>
|
/// <para>
|
||||||
|
/// Original code by Javier Arevalo (jare at iguanademos dot com). Rewritten
|
||||||
|
/// to C# / .NET by Markus Ewald (cygon at nuclex dot org).
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
/// You have a bunch of rectangular pieces. You need to arrange them in a
|
/// You have a bunch of rectangular pieces. You need to arrange them in a
|
||||||
/// rectangular surface so that they don't overlap, keeping the total area of the
|
/// rectangular surface so that they don't overlap, keeping the total area of the
|
||||||
/// rectangle as small as possible. This is fairly common when arranging characters
|
/// rectangle as small as possible. This is fairly common when arranging characters
|
||||||
|
@ -95,10 +99,10 @@ namespace Nuclex.Support.Packing {
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
/// <summary>Initializes a new rectangle packer</summary>
|
/// <summary>Initializes a new rectangle packer</summary>
|
||||||
/// <param name="maxPackingAreaWidth">Maximum width of the packing area</param>
|
/// <param name="packingAreaWidth">Maximum width of the packing area</param>
|
||||||
/// <param name="maxPackingAreaHeight">Maximum height of the packing area</param>
|
/// <param name="packingAreaHeight">Maximum height of the packing area</param>
|
||||||
public ArevaloRectanglePacker(int maxPackingAreaWidth, int maxPackingAreaHeight)
|
public ArevaloRectanglePacker(int packingAreaWidth, int packingAreaHeight)
|
||||||
: base(maxPackingAreaWidth, maxPackingAreaHeight) {
|
: base(packingAreaWidth, packingAreaHeight) {
|
||||||
|
|
||||||
this.packedRectangles = new List<Rectangle>();
|
this.packedRectangles = new List<Rectangle>();
|
||||||
this.anchors = new List<Point>();
|
this.anchors = new List<Point>();
|
||||||
|
@ -113,7 +117,7 @@ namespace Nuclex.Support.Packing {
|
||||||
/// <param name="rectangleHeight">Height of the rectangle to allocate</param>
|
/// <param name="rectangleHeight">Height of the rectangle to allocate</param>
|
||||||
/// <param name="placement">Output parameter receiving the rectangle's placement</param>
|
/// <param name="placement">Output parameter receiving the rectangle's placement</param>
|
||||||
/// <returns>True if space for the rectangle could be allocated</returns>
|
/// <returns>True if space for the rectangle could be allocated</returns>
|
||||||
public override bool TryAllocate(
|
public override bool TryPack(
|
||||||
int rectangleWidth, int rectangleHeight, out Point placement
|
int rectangleWidth, int rectangleHeight, out Point placement
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
@ -181,8 +185,8 @@ namespace Nuclex.Support.Packing {
|
||||||
// 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 < MaxPackingAreaWidth);
|
bool canEnlargeWidth = (packingAreaWidth < PackingAreaWidth);
|
||||||
bool canEnlargeHeight = (packingAreaHeight < MaxPackingAreaHeight);
|
bool canEnlargeHeight = (packingAreaHeight < 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)
|
||||||
|
@ -195,7 +199,7 @@ namespace Nuclex.Support.Packing {
|
||||||
// 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, MaxPackingAreaHeight)
|
packingAreaWidth, Math.Min(packingAreaHeight * 2, PackingAreaHeight)
|
||||||
);
|
);
|
||||||
|
|
||||||
} else if(canEnlargeWidth) {
|
} else if(canEnlargeWidth) {
|
||||||
|
@ -203,7 +207,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, MaxPackingAreaWidth), packingAreaHeight
|
Math.Min(packingAreaWidth * 2, PackingAreaWidth), packingAreaHeight
|
||||||
);
|
);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -24,13 +24,20 @@ using Microsoft.Xna.Framework;
|
||||||
|
|
||||||
namespace Nuclex.Support.Packing {
|
namespace Nuclex.Support.Packing {
|
||||||
|
|
||||||
/// <summary>Packer using a custom algorithm by Markus Ewald</summary>
|
/// <summary>Packer using a custom algorithm by Markus 'Cygon' Ewald</summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// This algorithms always places as close to the top as possible. So, for any new
|
/// <para>
|
||||||
/// rectangle, the packer has to determine a X coordinate at which the rectangle
|
/// Algorithm conceived by Markus Ewald (cygon at nuclex dot org), thought
|
||||||
/// can be placed at the highest point. To quickly discover these locations,
|
/// I'm quite sure I'm not the first one to invent this algorithm :)
|
||||||
/// the packer keeps a dynamically list of "height slices", which store the
|
/// </para>
|
||||||
/// baseline of the rectangles that have been placed so far.
|
/// <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.
|
||||||
|
/// </para>
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public class CygonRectanglePacker : RectanglePacker {
|
public class CygonRectanglePacker : RectanglePacker {
|
||||||
|
|
||||||
|
@ -55,10 +62,10 @@ namespace Nuclex.Support.Packing {
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
/// <summary>Initializes a new rectangle packer</summary>
|
/// <summary>Initializes a new rectangle packer</summary>
|
||||||
/// <param name="maxPackingAreaWidth">Maximum width of the packing area</param>
|
/// <param name="packingAreaWidth">Maximum width of the packing area</param>
|
||||||
/// <param name="maxPackingAreaHeight">Maximum height of the packing area</param>
|
/// <param name="packingAreaHeight">Maximum height of the packing area</param>
|
||||||
public CygonRectanglePacker(int maxPackingAreaWidth, int maxPackingAreaHeight)
|
public CygonRectanglePacker(int packingAreaWidth, int packingAreaHeight)
|
||||||
: base(maxPackingAreaWidth, maxPackingAreaHeight) {
|
: base(packingAreaWidth, packingAreaHeight) {
|
||||||
|
|
||||||
this.heightSlices = new List<Point>();
|
this.heightSlices = new List<Point>();
|
||||||
|
|
||||||
|
@ -72,41 +79,37 @@ namespace Nuclex.Support.Packing {
|
||||||
/// <param name="rectangleHeight">Height of the rectangle to allocate</param>
|
/// <param name="rectangleHeight">Height of the rectangle to allocate</param>
|
||||||
/// <param name="placement">Output parameter receiving the rectangle's placement</param>
|
/// <param name="placement">Output parameter receiving the rectangle's placement</param>
|
||||||
/// <returns>True if space for the rectangle could be allocated</returns>
|
/// <returns>True if space for the rectangle could be allocated</returns>
|
||||||
public override bool TryAllocate(
|
public override bool TryPack(
|
||||||
int rectangleWidth, int rectangleHeight, out Point placement
|
int rectangleWidth, int rectangleHeight, out Point placement
|
||||||
) {
|
) {
|
||||||
int sliceIndex = findBestPosition(rectangleWidth, rectangleHeight);
|
// If the rectangle is larger than the packing area in any dimension,
|
||||||
|
// it will never fit!
|
||||||
// TODO: Rectangle might not even fit there!
|
if(
|
||||||
if(sliceIndex == -1) {
|
(rectangleWidth > PackingAreaWidth) || (rectangleHeight > PackingAreaHeight)
|
||||||
|
) {
|
||||||
placement = Point.Zero;
|
placement = Point.Zero;
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
placement = this.heightSlices[sliceIndex];
|
|
||||||
|
|
||||||
integrateRectangle(
|
|
||||||
this.heightSlices[sliceIndex].X,
|
|
||||||
rectangleWidth,
|
|
||||||
this.heightSlices[sliceIndex].Y + rectangleHeight
|
|
||||||
);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool fits = findBestPosition(rectangleWidth, rectangleHeight, out placement);
|
||||||
|
if(fits)
|
||||||
|
integrateRectangle(placement.X, rectangleWidth, placement.Y + rectangleHeight);
|
||||||
|
|
||||||
|
return fits;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Finds the best position for a rectangle of the given width</summary>
|
/// <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="rectangleWidth">Width of the rectangle to find a position for</param>
|
||||||
/// <param name="rectangleHeight">Height 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>
|
/// <returns>The best position for a rectangle with the specified width</returns>
|
||||||
private int findBestPosition(int rectangleWidth, int rectangleHeight) {
|
private bool findBestPosition(
|
||||||
|
int rectangleWidth, int rectangleHeight, out Point placement
|
||||||
|
) {
|
||||||
|
|
||||||
// Index and score of the best slice we could find for the rectangle
|
// Slice index, vertical position and score of the best placement we could find
|
||||||
int bestSliceIndex = -1;
|
int bestSliceIndex = -1; // Slice index where the best placement was found
|
||||||
int bestScore = MaxPackingAreaWidth * MaxPackingAreaHeight; // lower == better!
|
int bestSliceY = 0; // Y position of the best placement found
|
||||||
|
int bestScore = PackingAreaWidth * PackingAreaHeight; // lower == better!
|
||||||
|
|
||||||
// This is the counter for the currently checked position. The search works by
|
// This is the counter for the currently checked position. The search works by
|
||||||
// skipping from slice to slice, determining the suitability of the location for the
|
// skipping from slice to slice, determining the suitability of the location for the
|
||||||
|
@ -130,11 +133,11 @@ namespace Nuclex.Support.Packing {
|
||||||
if(this.heightSlices[index].Y > highest)
|
if(this.heightSlices[index].Y > highest)
|
||||||
highest = this.heightSlices[index].Y;
|
highest = this.heightSlices[index].Y;
|
||||||
|
|
||||||
if((highest + rectangleHeight < MaxPackingAreaHeight)) {
|
if((highest + rectangleHeight < PackingAreaHeight)) {
|
||||||
int score = highest;
|
int score = highest;
|
||||||
|
|
||||||
// TESTING --------------------------------------------------
|
// WASTED AREA CALCULATION --------------------------------------------------
|
||||||
/*
|
|
||||||
// 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
|
||||||
int wastedArea = 0;
|
int wastedArea = 0;
|
||||||
|
@ -149,14 +152,13 @@ namespace Nuclex.Support.Packing {
|
||||||
this.heightSlices[rightSliceIndex - 1].X
|
this.heightSlices[rightSliceIndex - 1].X
|
||||||
);
|
);
|
||||||
|
|
||||||
//score += Math.Sign(wastedArea);
|
score += (int)Math.Sqrt((double)wastedArea) / 10;
|
||||||
//score += (int)Math.Sqrt((double)wastedArea);
|
|
||||||
//score = wastedArea;
|
// WASTED AREA CALCULATION --------------------------------------------------
|
||||||
*/
|
|
||||||
// TESTING --------------------------------------------------
|
|
||||||
|
|
||||||
if(score < bestScore) {
|
if(score < bestScore) {
|
||||||
bestSliceIndex = leftSliceIndex;
|
bestSliceIndex = leftSliceIndex;
|
||||||
|
bestSliceY = highest;
|
||||||
bestScore = score;
|
bestScore = score;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -172,7 +174,7 @@ namespace Nuclex.Support.Packing {
|
||||||
for(; rightSliceIndex <= this.heightSlices.Count; ++rightSliceIndex) {
|
for(; rightSliceIndex <= this.heightSlices.Count; ++rightSliceIndex) {
|
||||||
int rightSliceStart;
|
int rightSliceStart;
|
||||||
if(rightSliceIndex == this.heightSlices.Count)
|
if(rightSliceIndex == this.heightSlices.Count)
|
||||||
rightSliceStart = MaxPackingAreaWidth;
|
rightSliceStart = PackingAreaWidth;
|
||||||
else
|
else
|
||||||
rightSliceStart = this.heightSlices[rightSliceIndex].X;
|
rightSliceStart = this.heightSlices[rightSliceIndex].X;
|
||||||
|
|
||||||
|
@ -190,7 +192,13 @@ namespace Nuclex.Support.Packing {
|
||||||
|
|
||||||
// Return the index of the best slice we found for this rectangle. If the rectangle
|
// 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.
|
// didn't fit, this variable will still have its initialization value of -1.
|
||||||
return bestSliceIndex;
|
if(bestSliceIndex == -1) {
|
||||||
|
placement = Point.Zero;
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
placement = new Point(this.heightSlices[bestSliceIndex].X, bestSliceY);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -234,7 +242,7 @@ namespace Nuclex.Support.Packing {
|
||||||
// If the slice ends within the last slice (usual case, unless it has the
|
// If the slice ends within the last slice (usual case, unless it has the
|
||||||
// exact same width the packing area has), add another slice to return to
|
// exact same width the packing area has), add another slice to return to
|
||||||
// the original height at the end of the rectangle.
|
// the original height at the end of the rectangle.
|
||||||
if(right < MaxPackingAreaWidth)
|
if(right < PackingAreaWidth)
|
||||||
this.heightSlices.Add(new Point(right, firstSliceOriginalHeight));
|
this.heightSlices.Add(new Point(right, firstSliceOriginalHeight));
|
||||||
|
|
||||||
} else { // The rectangle doesn't start on the last slice
|
} else { // The rectangle doesn't start on the last slice
|
||||||
|
@ -264,7 +272,7 @@ namespace Nuclex.Support.Packing {
|
||||||
// Remove all slices covered by the rectangle and begin a new slice at its end
|
// Remove all slices covered by the rectangle and begin a new slice at its end
|
||||||
// to return back to the height of the slice on which the rectangle ends.
|
// to return back to the height of the slice on which the rectangle ends.
|
||||||
this.heightSlices.RemoveRange(startSlice, endSlice - startSlice);
|
this.heightSlices.RemoveRange(startSlice, endSlice - startSlice);
|
||||||
if(right < MaxPackingAreaWidth)
|
if(right < PackingAreaWidth)
|
||||||
this.heightSlices.Insert(startSlice, new Point(right, returnHeight));
|
this.heightSlices.Insert(startSlice, new Point(right, returnHeight));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ namespace Nuclex.Support.Packing {
|
||||||
for(int size = 24; size >= 1; --size) {
|
for(int size = 24; size >= 1; --size) {
|
||||||
Point placement;
|
Point placement;
|
||||||
|
|
||||||
if(packer.TryAllocate(size, size, out placement))
|
if(packer.TryPack(size, size, out placement))
|
||||||
areaCovered += size * size;
|
areaCovered += size * size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,28 +32,28 @@ namespace Nuclex.Support.Packing {
|
||||||
/// performant one for a given job.
|
/// performant one for a given job.
|
||||||
/// </para>
|
/// </para>
|
||||||
/// <para>
|
/// <para>
|
||||||
/// An almost exhaustive list of rectangle packers can be found here:
|
/// An almost exhaustive list of packing algorithms can be found here:
|
||||||
/// http://www.csc.liv.ac.uk/~epa/surveyhtml.html
|
/// http://www.csc.liv.ac.uk/~epa/surveyhtml.html
|
||||||
/// </para>
|
/// </para>
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public abstract class RectanglePacker {
|
public abstract class RectanglePacker {
|
||||||
|
|
||||||
/// <summary>Initializes a new rectangle packer</summary>
|
/// <summary>Initializes a new rectangle packer</summary>
|
||||||
/// <param name="maxPackingAreaWidth">Maximum width of the packing area</param>
|
/// <param name="packingAreaWidth">Width of the packing area</param>
|
||||||
/// <param name="maxPackingAreaHeight">Maximum height of the packing area</param>
|
/// <param name="packingAreaHeight">Height of the packing area</param>
|
||||||
protected RectanglePacker(int maxPackingAreaWidth, int maxPackingAreaHeight) {
|
protected RectanglePacker(int packingAreaWidth, int packingAreaHeight) {
|
||||||
this.maxPackingAreaWidth = maxPackingAreaWidth;
|
this.packingAreaWidth = packingAreaWidth;
|
||||||
this.maxPackingAreaHeight = maxPackingAreaHeight;
|
this.packingAreaHeight = packingAreaHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Allocates space for a rectangle in the packing area</summary>
|
/// <summary>Allocates space for a rectangle in the packing area</summary>
|
||||||
/// <param name="rectangleWidth">Width of the rectangle to allocate</param>
|
/// <param name="rectangleWidth">Width of the rectangle to allocate</param>
|
||||||
/// <param name="rectangleHeight">Height of the rectangle to allocate</param>
|
/// <param name="rectangleHeight">Height of the rectangle to allocate</param>
|
||||||
/// <returns>The location at which the rectangle has been placed</returns>
|
/// <returns>The location at which the rectangle has been placed</returns>
|
||||||
public virtual Point Allocate(int rectangleWidth, int rectangleHeight) {
|
public virtual Point Pack(int rectangleWidth, int rectangleHeight) {
|
||||||
Point point;
|
Point point;
|
||||||
|
|
||||||
if(!TryAllocate(rectangleWidth, rectangleHeight, out point))
|
if(!TryPack(rectangleWidth, rectangleHeight, out point))
|
||||||
throw new Exception("Rectangle does not fit in packing area");
|
throw new Exception("Rectangle does not fit in packing area");
|
||||||
|
|
||||||
return point;
|
return point;
|
||||||
|
@ -64,24 +64,24 @@ namespace Nuclex.Support.Packing {
|
||||||
/// <param name="rectangleHeight">Height of the rectangle to allocate</param>
|
/// <param name="rectangleHeight">Height of the rectangle to allocate</param>
|
||||||
/// <param name="placement">Output parameter receiving the rectangle's placement</param>
|
/// <param name="placement">Output parameter receiving the rectangle's placement</param>
|
||||||
/// <returns>True if space for the rectangle could be allocated</returns>
|
/// <returns>True if space for the rectangle could be allocated</returns>
|
||||||
public abstract bool TryAllocate(
|
public abstract bool TryPack(
|
||||||
int rectangleWidth, int rectangleHeight, out Point placement
|
int rectangleWidth, int rectangleHeight, out Point placement
|
||||||
);
|
);
|
||||||
|
|
||||||
/// <summary>Maximum width the packing area is allowed to have</summary>
|
/// <summary>Maximum width the packing area is allowed to have</summary>
|
||||||
protected int MaxPackingAreaWidth {
|
protected int PackingAreaWidth {
|
||||||
get { return this.maxPackingAreaWidth; }
|
get { return this.packingAreaWidth; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Maximum height the packing area is allowed to have</summary>
|
/// <summary>Maximum height the packing area is allowed to have</summary>
|
||||||
protected int MaxPackingAreaHeight {
|
protected int PackingAreaHeight {
|
||||||
get { return this.maxPackingAreaHeight; }
|
get { return this.packingAreaHeight; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Maximum allowed width of the packing area</summary>
|
/// <summary>Maximum allowed width of the packing area</summary>
|
||||||
private int maxPackingAreaWidth;
|
private int packingAreaWidth;
|
||||||
/// <summary>Maximum allowed height of the packing area</summary>
|
/// <summary>Maximum allowed height of the packing area</summary>
|
||||||
private int maxPackingAreaHeight;
|
private int packingAreaHeight;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,38 +34,38 @@ namespace Nuclex.Support.Packing {
|
||||||
public class SimpleRectanglePacker : RectanglePacker {
|
public class SimpleRectanglePacker : RectanglePacker {
|
||||||
|
|
||||||
/// <summary>Initializes a new rectangle packer</summary>
|
/// <summary>Initializes a new rectangle packer</summary>
|
||||||
/// <param name="maxPackingAreaWidth">Maximum width of the packing area</param>
|
/// <param name="packingAreaWidth">Maximum width of the packing area</param>
|
||||||
/// <param name="maxPackingAreaHeight">Maximum height of the packing area</param>
|
/// <param name="packingAreaHeight">Maximum height of the packing area</param>
|
||||||
public SimpleRectanglePacker(int maxPackingAreaWidth, int maxPackingAreaHeight)
|
public SimpleRectanglePacker(int packingAreaWidth, int packingAreaHeight)
|
||||||
: base(maxPackingAreaWidth, maxPackingAreaHeight) { }
|
: base(packingAreaWidth, packingAreaHeight) { }
|
||||||
|
|
||||||
/// <summary>Tries to allocate space for a rectangle in the packing area</summary>
|
/// <summary>Tries to allocate space for a rectangle in the packing area</summary>
|
||||||
/// <param name="rectangleWidth">Width of the rectangle to allocate</param>
|
/// <param name="rectangleWidth">Width of the rectangle to allocate</param>
|
||||||
/// <param name="rectangleHeight">Height of the rectangle to allocate</param>
|
/// <param name="rectangleHeight">Height of the rectangle to allocate</param>
|
||||||
/// <param name="placement">Output parameter receiving the rectangle's placement</param>
|
/// <param name="placement">Output parameter receiving the rectangle's placement</param>
|
||||||
/// <returns>True if space for the rectangle could be allocated</returns>
|
/// <returns>True if space for the rectangle could be allocated</returns>
|
||||||
public override bool TryAllocate(
|
public override bool TryPack(
|
||||||
int rectangleWidth, int rectangleHeight, out Point placement
|
int rectangleWidth, int rectangleHeight, out Point placement
|
||||||
) {
|
) {
|
||||||
|
|
||||||
// If the rectangle is larger than the packing area in any dimension,
|
// If the rectangle is larger than the packing area in any dimension,
|
||||||
// it will never fit!
|
// it will never fit!
|
||||||
if(
|
if(
|
||||||
(rectangleWidth > MaxPackingAreaWidth) || (rectangleHeight > MaxPackingAreaHeight)
|
(rectangleWidth > PackingAreaWidth) || (rectangleHeight > PackingAreaHeight)
|
||||||
) {
|
) {
|
||||||
placement = Point.Zero;
|
placement = Point.Zero;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do we have to start a new line ?
|
// Do we have to start a new line ?
|
||||||
if(this.column + rectangleWidth > MaxPackingAreaWidth) {
|
if(this.column + rectangleWidth > PackingAreaWidth) {
|
||||||
this.currentLine += this.lineHeight;
|
this.currentLine += this.lineHeight;
|
||||||
this.lineHeight = 0;
|
this.lineHeight = 0;
|
||||||
this.column = 0;
|
this.column = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If it doesn't fit vertically now, the packing area is considered full
|
// If it doesn't fit vertically now, the packing area is considered full
|
||||||
if(this.currentLine + rectangleHeight > MaxPackingAreaHeight) {
|
if(this.currentLine + rectangleHeight > PackingAreaHeight) {
|
||||||
placement = Point.Zero;
|
placement = Point.Zero;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user