File: RectF.cs
Web Access
Project: src\src\Graphics\src\Graphics\Graphics.csproj (Microsoft.Maui.Graphics)
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
 
namespace Microsoft.Maui.Graphics
{
	[DebuggerDisplay("X={X}, Y={Y}, Width={Width}, Height={Height}")]
	[TypeConverter(typeof(Converters.RectFTypeConverter))]
	public partial struct RectF
	{
		public float X { get; set; }
 
		public float Y { get; set; }
 
		public float Width { get; set; }
 
		public float Height { get; set; }
 
		public static RectF Zero = new RectF();
 
		public override string ToString()
		{
			return string.Format("{{X={0} Y={1} Width={2} Height={3}}}", X.ToString(CultureInfo.InvariantCulture), Y.ToString(CultureInfo.InvariantCulture), Width.ToString(CultureInfo.InvariantCulture),
				Height.ToString(CultureInfo.InvariantCulture));
		}
 
		// constructors
		public RectF(float x, float y, float width, float height) : this()
		{
			X = x;
			Y = y;
			Width = width;
			Height = height;
		}
 
		public RectF(PointF loc, SizeF sz) : this(loc.X, loc.Y, sz.Width, sz.Height)
		{
		}
 
		public static RectF FromLTRB(float left, float top, float right, float bottom)
		{
			return new RectF(left, top, right - left, bottom - top);
		}
 
		public bool Equals(RectF other)
		{
			return X.Equals(other.X) && Y.Equals(other.Y) && Width.Equals(other.Width) && Height.Equals(other.Height);
		}
 
		public override bool Equals(object obj)
		{
			if (obj is null)
				return false;
			return obj is RectF && Equals((RectF)obj);
		}
 
		public override int GetHashCode()
		{
			unchecked
			{
				int hashCode = X.GetHashCode();
				hashCode = (hashCode * 397) ^ Y.GetHashCode();
				hashCode = (hashCode * 397) ^ Width.GetHashCode();
				hashCode = (hashCode * 397) ^ Height.GetHashCode();
				return hashCode;
			}
		}
 
		public static bool operator ==(RectF r1, RectF r2)
		{
			return r1.Equals(r2);
		}
 
		public static bool operator !=(RectF r1, RectF r2)
		{
			return !(r1 == r2);
		}
 
		// Hit Testing / Intersection / Union
		public bool Contains(RectF rect)
		{
			return X <= rect.X && Right >= rect.Right && Y <= rect.Y && Bottom >= rect.Bottom;
		}
 
		public bool Contains(PointF pt)
		{
			return Contains(pt.X, pt.Y);
		}
 
		public bool Contains(float x, float y)
		{
			return (x >= Left) && (x < Right) && (y >= Top) && (y < Bottom);
		}
 
		public bool IntersectsWith(RectF r)
		{
			return !((Left >= r.Right) || (Right <= r.Left) || (Top >= r.Bottom) || (Bottom <= r.Top));
		}
 
		public RectF Union(RectF r)
		{
			return Union(this, r);
		}
 
		public static RectF Union(RectF r1, RectF r2)
		{
			return FromLTRB(Math.Min(r1.Left, r2.Left), Math.Min(r1.Top, r2.Top), Math.Max(r1.Right, r2.Right), Math.Max(r1.Bottom, r2.Bottom));
		}
 
		public RectF Intersect(RectF r)
		{
			return Intersect(this, r);
		}
 
		public static RectF Intersect(RectF r1, RectF r2)
		{
			float x = Math.Max(r1.X, r2.X);
			float y = Math.Max(r1.Y, r2.Y);
			float width = Math.Min(r1.Right, r2.Right) - x;
			float height = Math.Min(r1.Bottom, r2.Bottom) - y;
 
			if (width < 0 || height < 0)
			{
				return Zero;
			}
			return new RectF(x, y, width, height);
		}
 
		// Position/Size
		public float Top
		{
			get => Y;
			set => Y = value;
		}
 
		public float Bottom
		{
			get => Y + Height;
			set => Height = value - Y;
		}
 
		public float Right
		{
			get => X + Width;
			set => Width = value - X;
		}
 
		public float Left
		{
			get => X;
			set => X = value;
		}
 
		public bool IsEmpty => (Width <= 0) || (Height <= 0);
 
		public SizeF Size
		{
			get => new SizeF(Width, Height);
			set
			{
				Width = value.Width;
				Height = value.Height;
			}
		}
 
		public PointF Location
		{
			get => new PointF(X, Y);
			set
			{
				X = value.X;
				Y = value.Y;
			}
		}
 
		public PointF Center => new PointF(X + Width / 2, Y + Height / 2);
 
		// Inflate and Offset
		public RectF Inflate(SizeF sz)
		{
			return Inflate(sz.Width, sz.Height);
		}
 
		public RectF Inflate(float width, float height)
		{
			RectF r = this;
			r.X -= width;
			r.Y -= height;
			r.Width += width * 2;
			r.Height += height * 2;
			return r;
		}
 
		public RectF Offset(float dx, float dy)
		{
			RectF r = this;
			r.X += dx;
			r.Y += dy;
			return r;
		}
 
		public RectF Offset(PointF dr)
		{
			return Offset(dr.X, dr.Y);
		}
 
		public RectF Round()
		{
			return new RectF(MathF.Round(X), MathF.Round(Y), MathF.Round(Width), MathF.Round(Height));
		}
 
		public void Deconstruct(out float x, out float y, out float width, out float height)
		{
			x = X;
			y = Y;
			width = Width;
			height = Height;
		}
 
		public static implicit operator Rect(RectF rect) => new Rect(rect.X, rect.Y, rect.Width, rect.Height);
 
		public static bool TryParse(string value, out RectF rectangleF)
		{
			if (!string.IsNullOrEmpty(value))
			{
				string[] xywh = value.Split(',');
				if (xywh.Length == 4
					&& float.TryParse(xywh[0], NumberStyles.Number, CultureInfo.InvariantCulture, out float x)
					&& float.TryParse(xywh[1], NumberStyles.Number, CultureInfo.InvariantCulture, out float y)
					&& float.TryParse(xywh[2], NumberStyles.Number, CultureInfo.InvariantCulture, out float w)
					&& float.TryParse(xywh[3], NumberStyles.Number, CultureInfo.InvariantCulture, out float h))
				{
					rectangleF = new RectF(x, y, w, h);
					return true;
				}
			}
 
			rectangleF = default;
			return false;
		}
	}
}