/// <summary> /// Inflate - return the result of inflating rect by the size provided, in all directions /// If this is Empty, this method is illegal. /// </summary> public static Rect Inflate(Rect rect, double width, double height) { rect.Inflate(width, height); return rect; }
/// <summary> /// Offset - return the result of offsetting rect by the offset provided /// If this is Empty, this method is illegal. /// </summary> public static Rect Offset(Rect rect, double offsetX, double offsetY) { rect.Offset(offsetX, offsetY); return rect; }
/// <summary> /// Inflate - return the result of inflating rect by the size provided, in all directions /// If this is Empty, this method is illegal. /// </summary> public static Rect Inflate(Rect rect, Size size) { rect.Inflate(size._width, size._height); return rect; }
/// <summary> /// Union - Return the result of the union of rect and point. /// </summary> public static Rect Union(Rect rect, Point point) { rect.Union(new Rect(point, point)); return rect; }
/// <summary> /// Offset - return the result of offsetting rect by the offset provided /// If this is Empty, this method is illegal. /// </summary> public static Rect Offset(Rect rect, Vector offsetVector) { rect.Offset(offsetVector.X, offsetVector.Y); return rect; }
/// <summary> /// Compares two Rect instances for object equality. In this equality /// Double.NaN is equal to itself, unlike in numeric equality. /// Note that double values can acquire error when operated upon, such that /// an exact comparison between two values which /// are logically equal may fail. /// </summary> /// <returns> /// bool - true if the two Rect instances are exactly equal, false otherwise /// </returns> /// <param name='rect1'>The first Rect to compare</param> /// <param name='rect2'>The second Rect to compare</param> public static bool Equals(Rect rect1, Rect rect2) { if (rect1.IsEmpty) { return rect2.IsEmpty; } else { return rect1.X.Equals(rect2.X) && rect1.Y.Equals(rect2.Y) && rect1.Width.Equals(rect2.Width) && rect1.Height.Equals(rect2.Height); } }
/// <summary> /// rectHasNaN - this returns true if this rect has X, Y , Height or Width as NaN. /// </summary> /// <param name='r'>The rectangle to test</param> /// <returns>returns whether the Rect has NaN</returns> public static bool RectHasNaN(Rect r) { if (DoubleUtil.IsNaN(r.X) || DoubleUtil.IsNaN(r.Y) || DoubleUtil.IsNaN(r.Height) || DoubleUtil.IsNaN(r.Width)) { return true; } return false; }
/// <summary> /// Intersect - Update this rectangle to be the intersection of this and rect /// If either this or rect are Empty, the result is Empty as well. /// </summary> /// <param name="rect"> The rect to intersect with this </param> public void Intersect(Rect rect) { if (!this.IntersectsWith(rect)) { this = Empty; } else { double left = Math.Max(Left, rect.Left); double top = Math.Max(Top, rect.Top); // Max with 0 to prevent double weirdness from causing us to be (-epsilon..0) _width = Math.Max(Math.Min(Right, rect.Right) - left, 0); _height = Math.Max(Math.Min(Bottom, rect.Bottom) - top, 0); _x = left; _y = top; } }
/// <summary> /// Intersect - Return the result of the intersection of rect1 and rect2. /// If either this or rect are Empty, the result is Empty as well. /// </summary> public static Rect Intersect(Rect rect1, Rect rect2) { rect1.Intersect(rect2); return rect1; }
/// <summary> /// Contains - Returns true if the Rect non-Empty and is entirely contained within the /// rectangle, inclusive of the edges. /// Returns false otherwise /// </summary> public bool Contains(Rect rect) { if (IsEmpty || rect.IsEmpty) { return false; } return (_x <= rect._x && _y <= rect._y && _x + _width >= rect._x + rect._width && _y + _height >= rect._y + rect._height); }
/// <summary> /// IntersectsWith - Returns true if the Rect intersects with this rectangle /// Returns false otherwise. /// Note that if one edge is coincident, this is considered an intersection. /// </summary> /// <returns> /// Returns true if the Rect intersects with this rectangle /// Returns false otherwise. /// or Height /// </returns> /// <param name="rect"> Rect </param> public bool IntersectsWith(Rect rect) { if (IsEmpty || rect.IsEmpty) { return false; } return (rect.Left <= Right) && (rect.Right >= Left) && (rect.Top <= Bottom) && (rect.Bottom >= Top); }
/// <summary> /// TransformRect - Internal helper for perf /// </summary> /// <param name="rect"> The Rect to transform. </param> /// <param name="matrix"> The Matrix with which to transform the Rect. </param> internal static void TransformRect(ref Rect rect, ref Matrix matrix) { if (rect.IsEmpty) { return; } MatrixTypes matrixType = matrix._type; // If the matrix is identity, don't worry. if (matrixType == MatrixTypes.TRANSFORM_IS_IDENTITY) { return; } // Scaling if (0 != (matrixType & MatrixTypes.TRANSFORM_IS_SCALING)) { rect._x *= matrix._m11; rect._y *= matrix._m22; rect._width *= matrix._m11; rect._height *= matrix._m22; // Ensure the width is always positive. For example, if there was a reflection about the // y axis followed by a translation into the visual area, the width could be negative. if (rect._width < 0.0) { rect._x += rect._width; rect._width = -rect._width; } // Ensure the height is always positive. For example, if there was a reflection about the // x axis followed by a translation into the visual area, the height could be negative. if (rect._height < 0.0) { rect._y += rect._height; rect._height = -rect._height; } } // Translation if (0 != (matrixType & MatrixTypes.TRANSFORM_IS_TRANSLATION)) { // X rect._x += matrix._offsetX; // Y rect._y += matrix._offsetY; } if (matrixType == MatrixTypes.TRANSFORM_IS_UNKNOWN) { // Al Bunny implementation. Point point0 = matrix.Transform(rect.TopLeft); Point point1 = matrix.Transform(rect.TopRight); Point point2 = matrix.Transform(rect.BottomRight); Point point3 = matrix.Transform(rect.BottomLeft); // Width and height is always positive here. rect._x = Math.Min(Math.Min(point0.X, point1.X), Math.Min(point2.X, point3.X)); rect._y = Math.Min(Math.Min(point0.Y, point1.Y), Math.Min(point2.Y, point3.Y)); rect._width = Math.Max(Math.Max(point0.X, point1.X), Math.Max(point2.X, point3.X)) - rect._x; rect._height = Math.Max(Math.Max(point0.Y, point1.Y), Math.Max(point2.Y, point3.Y)) - rect._y; } }
/// <summary> /// Same as GetHomogeneousToViewportTransform3D but returns a 2D matrix. /// For detailed comments see: GetHomogeneousToViewportTransform3D /// </summary> internal static Matrix GetHomogeneousToViewportTransform(Rect viewport) { double sx = viewport.Width / 2; // half viewport width double sy = viewport.Height / 2; // half viewport height double tx = viewport.X + sx; double ty = viewport.Y + sy; return new Matrix( sx, 0, 0, -sy, tx, ty); }
/// <summary> /// GetHomogeneousToViewportTransform3D. /// /// Returns a matrix that performs the coordinate system change from /// /// 1 /// | /// -1 --------|------ 1 /// | /// -1 /// /// /// (Viewport.X, Viewport.Y) ---------- (Viewport.X + Viewport.Width, 0) /// | /// | /// | /// (Viewport.X, Viewport.Y + Viewport.Height) /// /// In other words, the viewport transform stretches the normalized coordinate /// system of [(-1, 1):(1, -1)] into the Viewport. /// </summary> internal static Matrix3D GetHomogeneousToViewportTransform3D(Rect viewport) { // Matrix3D scaling = new Matrix3D( // 1, 0, 0, 0, // 0, -1, 0, 0, // 0, 0, 1, 0, // 0, 0, 0, 1); // // Matrix3D translation = new Matrix3D( // 1, 0, 0, 0, // 0, 1, 0, 0, // 0, 0, 1, 0, // 1, 1, 0, 1); // // scaling * translation // // // == // // 1, 0, 0, 0, // 0, -1, 0, 0, // 0, 0, 1, 0, // 1, 1, 0, 1 // // // Matrix3D viewportScale = new Matrix3D( // Viewport.Width / 2, 0, 0, 0, // 0, Viewport.Height / 2, 0, 0, // 0, 0, 1, 0, // 0, 0, 0, 1); // // // * viewportScale // // == // // vw/2, 0, 0, 0, // 0, -vh/2, 0, 0, // 0, 0, 1, 0, // vw/2, vh/2, 0, 1, // // // Matrix3D viewportOffset = new Matrix3D( // 1, 0, 0, 0, // 0, 1, 0, 0, // 0, 0, 1, 0, // Viewport.X, Viewport.Y, 0, 1); // // // * viewportOffset // // == // // vw/2, 0, 0, 0, // 0, -vh/2, 0, 0, // 0, 0, 1, 0, // vw/2+vx, vh/2+vy, 0, 1 double sx = viewport.Width / 2; // half viewport width double sy = viewport.Height / 2; // half viewport height double tx = viewport.X + sx; double ty = viewport.Y + sy; return new Matrix3D( sx, 0, 0, 0, 0, -sy, 0, 0, 0, 0, 1, 0, tx, ty, 0, 1); }
/// <summary> /// Returns the bounds of the transformed rectangle. /// The Empty Rect is not affected by this call. /// </summary> /// <returns> /// The rect which results from the transformation. /// </returns> /// <param name="rect"> The Rect to transform. </param> /// <param name="matrix"> The Matrix by which to transform. </param> public static Rect Transform(Rect rect, Matrix matrix) { MatrixUtil.TransformRect(ref rect, ref matrix); return rect; }
/// <summary> /// Union - Update this rectangle to be the union of this and rect. /// </summary> public void Union(Rect rect) { if (IsEmpty) { this = rect; } else if (!rect.IsEmpty) { double left = Math.Min(Left, rect.Left); double top = Math.Min(Top, rect.Top); // We need this check so that the math does not result in NaN if ((rect.Width == Double.PositiveInfinity) || (Width == Double.PositiveInfinity)) { _width = Double.PositiveInfinity; } else { // Max with 0 to prevent double weirdness from causing us to be (-epsilon..0) double maxRight = Math.Max(Right, rect.Right); _width = Math.Max(maxRight - left, 0); } // We need this check so that the math does not result in NaN if ((rect.Height == Double.PositiveInfinity) || (Height == Double.PositiveInfinity)) { _height = Double.PositiveInfinity; } else { // Max with 0 to prevent double weirdness from causing us to be (-epsilon..0) double maxBottom = Math.Max(Bottom, rect.Bottom); _height = Math.Max(maxBottom - top, 0); } _x = left; _y = top; } }
static private Rect CreateEmptyRect() { Rect rect = new Rect(); // We can't set these via the property setters because negatives widths // are rejected in those APIs. rect._x = Double.PositiveInfinity; rect._y = Double.PositiveInfinity; rect._width = Double.NegativeInfinity; rect._height = Double.NegativeInfinity; return rect; }
/// <summary> /// Union - Return the result of the union of rect1 and rect2. /// </summary> public static Rect Union(Rect rect1, Rect rect2) { rect1.Union(rect2); return rect1; }
/// <summary> /// Equals - compares this Rect with the passed in object. In this equality /// Double.NaN is equal to itself, unlike in numeric equality. /// Note that double values can acquire error when operated upon, such that /// an exact comparison between two values which /// are logically equal may fail. /// </summary> /// <returns> /// bool - true if "value" is equal to "this". /// </returns> /// <param name='value'>The Rect to compare to "this"</param> public bool Equals(Rect value) { return Rect.Equals(this, value); }
/// <summary> /// Compares two rectangles for fuzzy equality. This function /// helps compensate for the fact that double values can /// acquire error when operated upon /// </summary> /// <param name='rect1'>The first rectangle to compare</param> /// <param name='rect2'>The second rectangle to compare</param> /// <returns>Whether or not the two rectangles are equal</returns> public static bool AreClose(Rect rect1, Rect rect2) { // If they're both empty, don't bother with the double logic. if (rect1.IsEmpty) { return rect2.IsEmpty; } // At this point, rect1 isn't empty, so the first thing we can test is // rect2.IsEmpty, followed by property-wise compares. return (!rect2.IsEmpty) && DoubleUtil.AreClose(rect1.X, rect2.X) && DoubleUtil.AreClose(rect1.Y, rect2.Y) && DoubleUtil.AreClose(rect1.Height, rect2.Height) && DoubleUtil.AreClose(rect1.Width, rect2.Width); }