using Newtonsoft.Json; using RhythmBase.Converters; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; namespace RhythmBase.Components { /// /// A point whose horizontal and vertical coordinates are nullable /// [JsonConverter(typeof(RDPointsConverter))] [DebuggerDisplay($"{{{nameof(GetDebuggerDisplay)}(),nq}}")] public struct RDPointE(RDExpression? x, RDExpression? y) : IRDVortex, IRDVortex, IRDVortex { /// /// Initializes a new instance of the struct with the specified size. /// /// The size to initialize the point with. public RDPointE(RDSize sz) : this(sz.Width, sz.Height) { } /// /// Initializes a new instance of the struct with the specified coordinates. /// /// The x-coordinate. /// The y-coordinate. public RDPointE(float x, float y) : this((RDExpression)x, (RDExpression)y) { } /// /// Initializes a new instance of the struct with the specified x-coordinate and y-coordinate. /// /// The x-coordinate. /// The y-coordinate. public RDPointE(RDExpression? x, float y) : this(x, (RDExpression)y) { } /// /// Initializes a new instance of the struct with the specified x-coordinate and y-coordinate. /// /// The x-coordinate. /// The y-coordinate. public RDPointE(float x, RDExpression? y) : this((RDExpression)x, y) { } /// /// Initializes a new instance of the struct with the specified x-coordinate and y-coordinate. /// /// The x-coordinate. /// The y-coordinate. public RDPointE(string x, float y) : this((RDExpression)x, (RDExpression)y) { } /// /// Initializes a new instance of the struct with the specified x-coordinate and y-coordinate. /// /// The x-coordinate. /// The y-coordinate. public RDPointE(float x, string y) : this((RDExpression)x, (RDExpression)y) { } /// /// Initializes a new instance of the struct with the specified x-coordinate and y-coordinate. /// /// The x-coordinate. /// The y-coordinate. public RDPointE(string x, RDExpression? y) : this((RDExpression)x, y) { } /// /// Initializes a new instance of the struct with the specified x-coordinate and y-coordinate. /// /// The x-coordinate. /// The y-coordinate. public RDPointE(RDExpression? x, string y) : this(x, (RDExpression)y) { } /// /// Initializes a new instance of the struct with the specified x-coordinate and y-coordinate. /// /// The x-coordinate. /// The y-coordinate. public RDPointE(string x, string y) : this((RDExpression)x, (RDExpression)y) { } /// /// Initializes a new instance of the struct with the specified point. /// /// The point to initialize the point with. public RDPointE(RDPointI p) : this(p.X, p.Y) { } /// /// Initializes a new instance of the struct with the specified point. /// /// The point to initialize the point with. public RDPointE(RDPoint p) : this(p.X, p.Y) { } /// public readonly bool IsEmpty => X == null && Y == null; /// public RDExpression? X { get; set; } = x; /// public RDExpression? Y { get; set; } = y; /// /// Offsets the point by the specified point. /// /// The point to offset by. public void Offset(RDPoint p) { X += p.X; Y += p.Y; } /// /// Offsets the point by the specified amounts. /// /// The amount to offset the x-coordinate. /// The amount to offset the y-coordinate. public void Offset(float? dx, float? dy) { X += dx; Y += dy; } /// /// Adds the specified size to the point. /// /// The point to add to. /// The size to add. /// The resulting point. public static RDPointE Add(RDPointE pt, RDSizeI sz) => new( pt.X + sz.Width, pt.Y + sz.Height ); /// public static RDPointE Add(RDPointE pt, RDSize sz) => new( pt.X + sz.Width, pt.Y + sz.Height ); /// public static RDPointE Add(RDPointE pt, RDSizeE sz) => new( pt.X + sz.Width, pt.Y + sz.Height ); /// /// Subtracts the specified size from the point. /// /// The point to subtract from. /// The size to subtract. /// The resulting point. public static RDPointE Subtract(RDPointE pt, RDSizeI sz) => new( pt.X - sz.Width, pt.Y - sz.Height ); /// public static RDPointE Subtract(RDPointE pt, RDSize sz) => new( pt.X - sz.Width, pt.Y - sz.Height ); /// public static RDPointE Subtract(RDPointE pt, RDSizeE sz) => new( pt.X - sz.Width, pt.Y - sz.Height ); /// public override readonly bool Equals([NotNullWhen(true)] object? obj) => obj is RDPointE e && Equals(e); /// public override readonly int GetHashCode() => HashCode.Combine(X, Y); /// public override readonly string ToString() => $"[{(X?.ExpressionValue) ?? "null"},{(Y?.ExpressionValue) ?? "null"}]"; /// public readonly bool Equals(RDPointE other) => other.X == X && other.Y == Y; /// /// Multiplies the point by the specified matrix. /// /// The matrix to multiply by. /// The resulting point. /// Thrown when the matrix is not 2x2. public readonly RDPointE MultipyByMatrix(RDExpression[,] matrix) { if (matrix.Rank == 2 && matrix.Length == 4) { RDPointE MultipyByMatrix = new( X * matrix[0, 0] + Y * matrix[1, 0], X * matrix[0, 1] + Y * matrix[1, 1]); return MultipyByMatrix; } throw new Exception("Matrix not match, 2*2 matrix expected."); } /// /// Rotate. /// public readonly RDPointE Rotate(float angle) { RDExpression[,] array = new RDExpression[2, 2]; array[0, 0] = (float)Math.Cos((double)angle); array[0, 1] = (float)Math.Sin((double)angle); array[1, 0] = (float)-(float)Math.Sin((double)angle); array[1, 1] = (float)Math.Cos((double)angle); return MultipyByMatrix(array); } /// /// Rotate at a given pivot. /// /// Given pivot. /// Angle. /// public readonly RDPointE Rotate(RDPointE pivot, float angle) => (this - new RDSizeE(pivot)).Rotate(angle) + new RDSizeE(pivot); /// public static RDPointE operator +(RDPointE pt, RDSizeI sz) => Add(pt, sz); /// public static RDPointE operator +(RDPointE pt, RDSize sz) => Add(pt, sz); /// public static RDPointE operator +(RDPointE pt, RDSizeE sz) => Add(pt, sz); /// public static RDPointE operator -(RDPointE pt, RDSizeI sz) => Subtract(pt, sz); /// public static RDPointE operator -(RDPointE pt, RDSize sz) => Subtract(pt, sz); /// public static RDPointE operator -(RDPointE pt, RDSizeE sz) => Subtract(pt, sz); /// public static RDPointE operator *(RDPointE pt, RDExpression x) => new(pt.X * x, pt.Y * x); /// public static RDPointE operator /(RDPointE pt, RDExpression x) => new(pt.X / x, pt.Y / x); /// public static bool operator ==(RDPointE left, RDPointE right) => left.Equals(right); /// public static bool operator !=(RDPointE left, RDPointE right) => !left.Equals(right); /// /// Converts the specified to an . /// /// The point to convert. /// An that represents the converted point. public static explicit operator RDSizeE(RDPointE p) => new(p); private readonly string GetDebuggerDisplay() => ToString(); } }