// "Therefore those skilled at the unorthodox // are infinite as heaven and earth, // inexhaustible as the great rivers. // When they come to an end, // they begin again, // like the days and months; // they die and are reborn, // like the four seasons." // // - Sun Tsu, // "The Art of War" using System; namespace TheArtOfDev.HtmlRenderer.Adapters.Entities { /// /// Stores a set of four floating-point numbers that represent the location and size of a rectangle. /// public struct RRect { #region Fields and Consts /// /// Represents an instance of the class with its members uninitialized. /// public static readonly RRect Empty = new RRect(); private double _height; private double _width; private double _x; private double _y; #endregion /// /// Initializes a new instance of the class with the specified location and size. /// /// The x-coordinate of the upper-left corner of the rectangle. /// The y-coordinate of the upper-left corner of the rectangle. /// The width of the rectangle. /// The height of the rectangle. public RRect(double x, double y, double width, double height) { _x = x; _y = y; _width = width; _height = height; } /// /// Initializes a new instance of the class with the specified location and size. /// /// A that represents the upper-left corner of the rectangular region. /// A that represents the width and height of the rectangular region. public RRect(RPoint location, RSize size) { _x = location.X; _y = location.Y; _width = size.Width; _height = size.Height; } /// /// Gets or sets the coordinates of the upper-left corner of this structure. /// /// A that represents the upper-left corner of this structure. public RPoint Location { get { return new RPoint(X, Y); } set { X = value.X; Y = value.Y; } } /// /// Gets or sets the size of this . /// /// A that represents the width and height of this structure. public RSize Size { get { return new RSize(Width, Height); } set { Width = value.Width; Height = value.Height; } } /// /// Gets or sets the x-coordinate of the upper-left corner of this structure. /// /// /// The x-coordinate of the upper-left corner of this structure. /// public double X { get { return _x; } set { _x = value; } } /// /// Gets or sets the y-coordinate of the upper-left corner of this structure. /// /// /// The y-coordinate of the upper-left corner of this structure. /// public double Y { get { return _y; } set { _y = value; } } /// /// Gets or sets the width of this structure. /// /// /// The width of this structure. /// public double Width { get { return _width; } set { _width = value; } } /// /// Gets or sets the height of this structure. /// /// /// The height of this structure. /// public double Height { get { return _height; } set { _height = value; } } /// /// Gets the x-coordinate of the left edge of this structure. /// /// /// The x-coordinate of the left edge of this structure. /// public double Left { get { return X; } } /// /// Gets the y-coordinate of the top edge of this structure. /// /// /// The y-coordinate of the top edge of this structure. /// public double Top { get { return Y; } } /// /// Gets the x-coordinate that is the sum of and /// /// of this structure. /// /// /// The x-coordinate that is the sum of and /// /// of this structure. /// public double Right { get { return X + Width; } } /// /// Gets the y-coordinate that is the sum of and /// /// of this structure. /// /// /// The y-coordinate that is the sum of and /// /// of this structure. /// public double Bottom { get { return Y + Height; } } /// /// Tests whether the or /// /// property of this has a value of zero. /// /// /// This property returns true if the or /// /// property of this has a value of zero; otherwise, false. /// public bool IsEmpty { get { if (Width > 0.0) return Height <= 0.0; else return true; } } /// /// Tests whether two structures have equal location and size. /// /// /// This operator returns true if the two specified structures have equal /// , , , and properties. /// /// /// The structure that is to the left of the equality operator. /// /// /// The structure that is to the right of the equality operator. /// public static bool operator ==(RRect left, RRect right) { if (Math.Abs(left.X - right.X) < 0.001 && Math.Abs(left.Y - right.Y) < 0.001 && Math.Abs(left.Width - right.Width) < 0.001) return Math.Abs(left.Height - right.Height) < 0.001; else return false; } /// /// Tests whether two structures differ in location or size. /// /// /// This operator returns true if any of the , /// , , or /// properties of the two structures are unequal; otherwise false. /// /// /// The structure that is to the left of the inequality operator. /// /// /// The structure that is to the right of the inequality operator. /// public static bool operator !=(RRect left, RRect right) { return !(left == right); } /// /// Creates a structure with upper-left corner and lower-right corner at the specified locations. /// /// /// The new that this method creates. /// /// The x-coordinate of the upper-left corner of the rectangular region. /// The y-coordinate of the upper-left corner of the rectangular region. /// The x-coordinate of the lower-right corner of the rectangular region. /// The y-coordinate of the lower-right corner of the rectangular region. public static RRect FromLTRB(double left, double top, double right, double bottom) { return new RRect(left, top, right - left, bottom - top); } /// /// Tests whether is a with the same location and size of this /// . /// /// /// This method returns true if is a and its X, Y, Width, and Height properties are equal to the corresponding properties of this /// ; otherwise, false. /// /// /// The to test. /// public override bool Equals(object obj) { if (!(obj is RRect)) return false; var rectangleF = (RRect)obj; if (Math.Abs(rectangleF.X - X) < 0.001 && Math.Abs(rectangleF.Y - Y) < 0.001 && Math.Abs(rectangleF.Width - Width) < 0.001) return Math.Abs(rectangleF.Height - Height) < 0.001; else return false; } /// /// Determines if the specified point is contained within this structure. /// /// /// This method returns true if the point defined by and is contained within this /// /// structure; otherwise false. /// /// The x-coordinate of the point to test. /// The y-coordinate of the point to test. public bool Contains(double x, double y) { if (X <= x && x < X + Width && Y <= y) return y < Y + Height; else return false; } /// /// Determines if the specified point is contained within this structure. /// /// /// This method returns true if the point represented by the parameter is contained within this /// /// structure; otherwise false. /// /// The to test. public bool Contains(RPoint pt) { return Contains(pt.X, pt.Y); } /// /// Determines if the rectangular region represented by is entirely contained within this /// /// structure. /// /// /// This method returns true if the rectangular region represented by is entirely contained within the rectangular region represented by this /// /// ; otherwise false. /// /// /// The to test. /// public bool Contains(RRect rect) { if (X <= rect.X && rect.X + rect.Width <= X + Width && Y <= rect.Y) return rect.Y + rect.Height <= Y + Height; else return false; } /// /// Inflates this structure by the specified amount. /// /// /// The amount to inflate this structure horizontally. /// /// /// The amount to inflate this structure vertically. /// public void Inflate(double x, double y) { X -= x; Y -= y; Width += 2f * x; Height += 2f * y; } /// /// Inflates this by the specified amount. /// /// The amount to inflate this rectangle. public void Inflate(RSize size) { Inflate(size.Width, size.Height); } /// /// Creates and returns an inflated copy of the specified structure. The copy is inflated by the specified amount. The original rectangle remains unmodified. /// /// /// The inflated . /// /// /// The to be copied. This rectangle is not modified. /// /// The amount to inflate the copy of the rectangle horizontally. /// The amount to inflate the copy of the rectangle vertically. public static RRect Inflate(RRect rect, double x, double y) { RRect rectangleF = rect; rectangleF.Inflate(x, y); return rectangleF; } /// /// Replaces this structure with the intersection of itself and the specified /// /// structure. /// /// The rectangle to intersect. public void Intersect(RRect rect) { RRect rectangleF = Intersect(rect, this); X = rectangleF.X; Y = rectangleF.Y; Width = rectangleF.Width; Height = rectangleF.Height; } /// /// Returns a structure that represents the intersection of two rectangles. If there is no intersection, and empty /// /// is returned. /// /// /// A third structure the size of which represents the overlapped area of the two specified rectangles. /// /// A rectangle to intersect. /// A rectangle to intersect. public static RRect Intersect(RRect a, RRect b) { double x = Math.Max(a.X, b.X); double num1 = Math.Min(a.X + a.Width, b.X + b.Width); double y = Math.Max(a.Y, b.Y); double num2 = Math.Min(a.Y + a.Height, b.Y + b.Height); if (num1 >= x && num2 >= y) return new RRect(x, y, num1 - x, num2 - y); else return Empty; } /// /// Determines if this rectangle intersects with . /// /// /// This method returns true if there is any intersection. /// /// The rectangle to test. public bool IntersectsWith(RRect rect) { if (rect.X < X + Width && X < rect.X + rect.Width && rect.Y < Y + Height) return Y < rect.Y + rect.Height; else return false; } /// /// Creates the smallest possible third rectangle that can contain both of two rectangles that form a union. /// /// /// A third structure that contains both of the two rectangles that form the union. /// /// A rectangle to union. /// A rectangle to union. public static RRect Union(RRect a, RRect b) { double x = Math.Min(a.X, b.X); double num1 = Math.Max(a.X + a.Width, b.X + b.Width); double y = Math.Min(a.Y, b.Y); double num2 = Math.Max(a.Y + a.Height, b.Y + b.Height); return new RRect(x, y, num1 - x, num2 - y); } /// /// Adjusts the location of this rectangle by the specified amount. /// /// The amount to offset the location. public void Offset(RPoint pos) { Offset(pos.X, pos.Y); } /// /// Adjusts the location of this rectangle by the specified amount. /// /// The amount to offset the location horizontally. /// The amount to offset the location vertically. public void Offset(double x, double y) { X += x; Y += y; } /// /// Gets the hash code for this structure. For information about the use of hash codes, see Object.GetHashCode. /// /// The hash code for this public override int GetHashCode() { return (int)(uint)X ^ ((int)(uint)Y << 13 | (int)((uint)Y >> 19)) ^ ((int)(uint)Width << 26 | (int)((uint)Width >> 6)) ^ ((int)(uint)Height << 7 | (int)((uint)Height >> 25)); } /// /// Converts the Location and Size of this to a human-readable string. /// /// /// A string that contains the position, width, and height of this structure for example, "{X=20, Y=20, Width=100, Height=50}". /// public override string ToString() { return "{X=" + X + ",Y=" + Y + ",Width=" + Width + ",Height=" + Height + "}"; } } }