using System.Diagnostics; using System.Diagnostics.CodeAnalysis; namespace RhythmBase.Components { /// /// Represents a rotated rectangle with non-integer coordinates. /// [DebuggerDisplay($"{{{nameof(GetDebuggerDisplay)}(),nq}}")] public struct RDRotatedRectE(RDPointE? location, RDSizeE? size, RDPointE? pivot, RDExpression? angle = null) : IEquatable { /// /// Gets or sets the location of the rectangle. /// public RDPointE? Location { get; set; } = location; /// /// Gets or sets the size of the rectangle. /// public RDSizeE? Size { get; set; } = size; /// /// Gets or sets the pivot point of the rotation. /// public RDPointE? Pivot { get; set; } = pivot; /// /// Gets or sets the angle of rotation in degrees. /// public RDExpression? Angle { get; set; } = angle; /// /// Gets the rectangle without rotation. /// public readonly RDRectE? WithoutRotate => Location is null && Pivot is null && Size is null ? null : new(Location - (RDSizeE)(Pivot??default), Size); /// /// IItializes a new instance of the struct. /// /// The rectangle. /// The pivot point. /// The angle of rotation. public RDRotatedRectE(RDRectE? rect, RDPointE? pivot, float angle) : this(rect?.Location, rect?.Size, pivot, angle) { } /// /// IItializes a new instance of the struct. /// /// The rectangle. public RDRotatedRectE(RDRectE? rect) : this(rect?.Location, rect?.Size, null, 0f) { } /// /// Inflates the specified rectangle by the specified size. /// /// The rectangle to inflate. /// The size to inflate by. /// The inflated rectangle. public static RDRotatedRectE Inflate(RDRotatedRectE rect, RDSizeE size) { RDRotatedRectE result = rect; result.Inflate(size); return result; } /// /// Inflates the specified rectangle by the specified width and height. /// /// The rectangle to inflate. /// The width to inflate by. /// The height to inflate by. /// The inflated rectangle. public static RDRotatedRectE Inflate(RDRotatedRectE rect, int x, int y) { RDRotatedRectE result = rect; result.Inflate(x, y); return result; } /// /// Offsets the rectangle by the specified x and y values. /// /// The x value to offset by. /// The y value to offset by. public void Offset(RDExpression? x, RDExpression? y) => Location += (RDSizeE)new RDPointE(x, y); /// /// Offsets the rectangle by the specified point. /// /// The point to offset by. public void Offset(RDPointE p) => Offset(p.X, p.Y); /// /// Inflates the rectangle by the specified size. /// /// The size to inflate by. public void Inflate(RDSizeE size) { Size += new RDSizeE(size.Width * 2, size.Height * 2); Pivot -= (RDSizeE)new RDPointE(size.Width, size.Height); } /// /// Inflates the rectangle by the specified width and height. /// /// The width to inflate by. /// The height to inflate by. public void Inflate(int width, int height) { Size += new RDSizeE(width * 2, height * 2); Pivot -= (RDSizeE)new RDPointE(width, height); } /// public static bool operator ==(RDRotatedRectE rect1, RDRotatedRectE rect2) => rect1.Equals(rect2); /// public static bool operator !=(RDRotatedRectE rect1, RDRotatedRectE rect2) => !rect1.Equals(rect2); /// public override readonly bool Equals([NotNullWhen(true)] object? obj) => obj is RDRotatedRectE e && Equals(e); /// public override readonly int GetHashCode() => HashCode.Combine(Location, Size, Pivot, Angle); /// public override readonly string ToString() => $"{{Location=[{Location}],Size=[{Size}],Pivot[{Pivot}],Angle={Angle}}}"; /// public readonly bool Equals(RDRotatedRectE other) => Location == other.Location && Size == other.Size && Pivot == other.Pivot && Angle == other.Angle; private readonly string GetDebuggerDisplay() => ToString(); } }