Implemented positionRect and supporting functions.
git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@4186 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
@@ -5,6 +5,26 @@ import flash.geom.Rectangle;
|
|||||||
|
|
||||||
public class DisplayUtil
|
public class DisplayUtil
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Returns the most reasonable position for the specified rectangle to
|
||||||
|
* be placed at so as to maximize its containment by the specified
|
||||||
|
* bounding rectangle while still placing it as near its original
|
||||||
|
* coordinates as possible.
|
||||||
|
*
|
||||||
|
* @param rect the rectangle to be positioned.
|
||||||
|
* @param bounds the containing rectangle.
|
||||||
|
*/
|
||||||
|
public static function fitRectInRect (
|
||||||
|
rect :Rectangle , bounds :Rectangle) :Point
|
||||||
|
{
|
||||||
|
// Guarantee that the right and bottom edges will be contained
|
||||||
|
// and do our best for the top and left edges.
|
||||||
|
var br :Point = bounds.bottomRight;
|
||||||
|
return new Point(
|
||||||
|
Math.min(br.x - rect.width, Math.max(rect.x, bounds.x)),
|
||||||
|
Math.min(br.y - rect.height, Math.max(rect.y, bounds.y)));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Position the specified rectangle within the bounds, avoiding
|
* Position the specified rectangle within the bounds, avoiding
|
||||||
* any of the Rectangles in the avoid array, which may be destructively
|
* any of the Rectangles in the avoid array, which may be destructively
|
||||||
@@ -18,8 +38,86 @@ public class DisplayUtil
|
|||||||
r :Rectangle, bounds :Rectangle, avoid :Array) :Boolean
|
r :Rectangle, bounds :Rectangle, avoid :Array) :Boolean
|
||||||
{
|
{
|
||||||
var origPos :Point = r.topLeft;
|
var origPos :Point = r.topLeft;
|
||||||
|
var pointSorter :Function = createPointSorter(origPos);
|
||||||
|
var possibles :Array = new Array();
|
||||||
|
// start things off with the passed-in point (adjusted to
|
||||||
|
// be inside the bounds, if needed)
|
||||||
|
possibles.push(fitRectInRect(r, bounds));
|
||||||
|
|
||||||
return true;
|
// keep track of area that doesn't generate new possibles
|
||||||
|
var dead :Array = new Array();
|
||||||
|
|
||||||
|
while (possibles.length > 0) {
|
||||||
|
try {
|
||||||
|
var p :Point = (possibles.shift() as Point);
|
||||||
|
r.x = p.x;
|
||||||
|
r.y = p.y;
|
||||||
|
|
||||||
|
// make sure the rectangle is in the view
|
||||||
|
if (!bounds.containsRect(r)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// and not over a dead area
|
||||||
|
for each (var deadRect :Rectangle in dead) {
|
||||||
|
if (deadRect.intersects(r)) {
|
||||||
|
throw true; // continue outer loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// see if it hits any rects we're trying to avoid
|
||||||
|
for (var ii :int = 0; ii < avoid.length; ii++) {
|
||||||
|
var avoidRect :Rectangle = (avoid[ii] as Rectangle);
|
||||||
|
if (avoidRect.intersects(r)) {
|
||||||
|
// remove it from the avoid list
|
||||||
|
avoid.splice(ii, 1);
|
||||||
|
// but add it to the dead list
|
||||||
|
dead.push(avoidRect);
|
||||||
|
|
||||||
|
// add 4 new possible points, each pushed in
|
||||||
|
// one direction
|
||||||
|
possibles.push(
|
||||||
|
new Point(avoidRect.x - r.width, r.y),
|
||||||
|
new Point(r.x, avoidRect.y - r.height),
|
||||||
|
new Point(avoidRect.x + avoidRect.width, r.y),
|
||||||
|
new Point(r.x, avoidRect.y + avoidRect.height));
|
||||||
|
|
||||||
|
// re-sort the list
|
||||||
|
possibles.sort(pointSorter);
|
||||||
|
throw true; // continue outer loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// hey! if we got here, then it worked!
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} catch (continueWhile :Boolean) {
|
||||||
|
// simply catch the boolean and use it to continue inner loops
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// we never found a match, move the rectangle back
|
||||||
|
r.x = origPos.x;
|
||||||
|
r.y = origPos.y;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a sort Function that can be used to compare Points in an
|
||||||
|
* Array according to their distance from the specified Point.
|
||||||
|
*
|
||||||
|
* Note: The function will always sort according to distance from the
|
||||||
|
* passed-in point, even if that point's coordinates change after
|
||||||
|
* the function is created.
|
||||||
|
*/
|
||||||
|
public static function createPointSorter (origin :Point) :Function
|
||||||
|
{
|
||||||
|
return function (p1 :Point, p2 :Point) :Number {
|
||||||
|
var dist1 :Number = Point.distance(origin, p1);
|
||||||
|
var dist2 :Number = Point.distance(origin, p2);
|
||||||
|
|
||||||
|
return (dist1 > dist2) ? 1 : ((dist1 < dist2) ? -1 : 0); // signum
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user