using System.Collections; using System.Drawing; using System.Numerics; namespace WebmrAPI.Utils.Sequences { public interface ISequenceGenerator : IEnumerable { public static bool IsZero(double val, double epsilon = Double.Epsilon) { return Math.Abs(val) < epsilon; } public T Min { get; } public T Max { get; } public double Progress { get; } public double Step { get; } public bool HasValues { get; } public T Next(); public ISequenceGenerator Reset(); } public interface INumberGenerator : ISequenceGenerator where T : struct, INumber { public INumberGenerator Self { get; } public virtual double DMin { get => Double.CreateChecked(Min); } public virtual double DMax { get => Double.CreateChecked(Max); } public virtual double Mean { get => (DMin + DMax) / 2.0; } } public interface IPointGenerator : ISequenceGenerator { public static double CalcDistance(Point pt1, Point pt2) { return Math.Sqrt(Math.Pow(pt1.X - pt2.X, 2) + Math.Pow(pt1.Y - pt2.Y, 2)); } public static double CalcAngle(Point pt1, Point pt2) { return Math.Atan2(pt2.Y - pt1.Y, pt2.X - pt1.X); } public static Point CalcPoint(double x, double y, double offset, double pAngle) { return new Point((int)Math.Round(x + offset * Math.Cos(pAngle)), (int)Math.Round(y + offset * Math.Sin(pAngle))); } public static Point CalcMiddle(Point start, Point end) { return new Point( (int)Math.Round(start.X + (end.X - start.X) / 2.0), (int)Math.Round(start.Y + (end.Y - start.Y) / 2.0) ); } public static (double distance, double angle) CalcDistanceAngle(Point pt1, Point pt2) { double dx = pt2.X - pt1.X; double dy = pt2.Y - pt1.Y; return (Math.Sqrt(Math.Pow(dx, 2) + Math.Pow(dy, 2)), Math.Atan2(dy, dx)); } public static double DegreesToRadians(double degrees) { return degrees * Math.PI / 180.0; } public static double RadiansToDegrees(double radians) { return radians * (180.0 / Math.PI); } public static Point NewPointAngleDistance(Point refPt, double distance, double aRadians, double epsilon = Double.Epsilon) { int x, y; if (IsZero(distance, epsilon)) return new Point(refPt.X, refPt.Y); x = (int)Math.Round(refPt.X + distance * Math.Cos(aRadians)); y = (int)Math.Round(refPt.Y + distance * Math.Sin(aRadians)); return new Point(x, y); } public static Point NewPointDistance(Point refPt, Point targetPt, double distance, double epsilon = Double.Epsilon) { return NewPointAngleDistance(refPt, distance, CalcAngle(refPt, targetPt), epsilon); } public static Point NewPointAngle(Point refPt, Point targetPt, double aRadians, double epsilon = Double.Epsilon) { return NewPointAngleDistance(refPt, CalcDistance(refPt, targetPt), aRadians, epsilon); } public static Point NewPointDistanceFactor(Point refPt, Point targetPt, double factor, double epsilon = Double.Epsilon) { return NewPointAngleDistance(refPt, CalcDistance(refPt, targetPt) * factor, CalcAngle(refPt, targetPt), epsilon); } public static Point GetRandomPointInRect(Rectangle rect) { double x = BaseRandom.NextGenerate(rect.X, rect.Width); double y = BaseRandom.NextGenerate(rect.Y, rect.Height); return new Point((int)Math.Round(x), (int)Math.Round(y)); } public IPointGenerator Self { get; } public virtual Point Start { get => Min; } public virtual Point End { get => Max; } public virtual double LinearX { get => Start.X + (End.X - Start.X) * Progress; } public virtual double LinearY { get => Start.Y + (End.Y - Start.Y) * Progress; } } public abstract class BaseGenerator : BaseRandom, ISequenceGenerator { protected virtual double Epsilon { get; set; } = 0.01; protected virtual bool IsZero(double val) { return ISequenceGenerator.IsZero(val, Epsilon); } private double _fShape = 1.0; private double _fFade = 0.5; public T Min { get; protected set; } public T Max { get; protected set; } public virtual double Progress { get; protected set; } = -1.0; public double ProgressRemainder { get => 1.0 - Progress; } public virtual bool HasValues { get; protected set; } = true; public double FShape { get => _fShape; protected set => _fShape = Math.Clamp(value, 0.0, 1.0); } public double FFade { get => _fFade; protected set => _fFade = Math.Clamp(value, Epsilon, 1.0); } protected double Scale { get => Math.Pow(Progress * ProgressRemainder * 4.0, FFade) * FShape; } public abstract double Step { get; protected set; } public BaseGenerator(T min, T max) { Min = min; Max = max; } protected static double CalcStepByCount(int count) { return 1.0 / count; } protected abstract T Calc(); protected virtual T First() => Calc(); protected virtual T Last() => Calc(); public virtual T Next() { if (Progress < 0) { Progress = 0; return First(); } if ((Progress += Step) >= 1.0) { HasValues = false; Progress = 1.0; return Last(); } return Calc(); } public virtual ISequenceGenerator Reset() { HasValues = true; Progress = -1.0; return this; } public IEnumerator GetEnumerator() { while (HasValues) { yield return Next(); } } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } }